---
name: fontana-agent-authoring
description: Write a Fontana agent package folder (AGENT.md and optional schedules.json) for upload on AI → Agent packages. Use when asked to create, draft, or export a Fontana agent, persona, or AGENT.md.
---

# Fontana agent authoring

You write a folder on disk. The operator uploads that folder with **Upload folder** on **AI → Agent packages** (`/ai/agents`). Fontana writes the folder into that namespace's `agents/` folder in Fontana Files and registers every `AGENT.md` it finds and, when present, the sibling `schedules.json`, once the files sync (usually a few seconds). A namespace is named exactly as the operator named it.

Operator guide: `https://fontana-ai.com/docs/ai/author-agents/`
This skill: `https://fontana-ai.com/docs/ai/agent-authoring-skill.md`

## What you produce

One package directory. Its name is the agent slug: lowercase, hyphenated, no spaces. `AGENT.md` sits directly inside that directory. No folder inside it holds another `AGENT.md` or a `SKILL.md`.

```text
nav-analyst/
├── AGENT.md            # Required
├── schedules.json      # Optional shared schedules
└── references/         # Optional reference files the agent reads on demand
    └── runbook.md
```

Every other file in the folder is a reference file: a runbook, a template, a sample. The agent sees a list of them (path and size) with its instructions on every turn and reads one with `skills_readPackageFile` (`self: true`, `path`). Keep the standing instructions in `AGENT.md`, move long material the agent needs only sometimes into a reference file, and name that file in the body with when to read it. `mailbox.yaml` and the `mailbox/` and `assets/` folders belong to the platform and are not reference files.

After upload into the `agents/` folder of a namespace the operator chooses, the agent id is the namespace plus the folder path. Example: this folder uploaded into `finance/agents/` is `finance/agents/nav-analyst`.

Upload into a namespace the operator created. Fontana's own agents live in `system`.

The folder path is the identity. Frontmatter omits `id` and `name`. A file that includes either key fails ingest.

## AGENT.md

The file starts with a YAML frontmatter block (`---` on the first line, closed by `---`) and continues with a Markdown system prompt. An empty body fails ingest.

### Keys ingest accepts

| Key | Required | What to write |
| --- | --- | --- |
| `title` | Yes | Display name in chat |
| `description` | Yes | One- or two-sentence catalog summary |
| `vectorSource` | Yes | Keywords for routing: role, domain nouns, deliverable names |
| `role` | No | Short job title, for example `NAV analyst` |
| `model` | No | Approved model id, or `""` for the deployment default |
| `scopes` | No | Where the agent can be picked. Omitted means `[chat]` |
| `abilities` | No | Map of ability id to `enabled` plus that ability's settings |
| `skills` | No | List of skill namespaces this agent may open skills from |
| `skillAutoLoad` | No | Map of `namespace/package` to a boolean auto-load override |
| `autoDiscoverSkills` | No | `false` turns off the first-turn skills catalog call. Omitted means on |
| `permissions` | No | Allow-list. Omitted means `["*"]` |
| `isActive` | No | `true` for a package the operator can pick |
| `reasoningEffort` | No | `none`, `minimal`, `low`, `medium`, `high`, or `xhigh` |
| `callSettings` | No | Mapping of model call fields (see below) |
| `voice` | No | Voice catalog id `provider::voiceKey`, only when the operator asked for speech |
| `icon` | No | Avatar asset reference: `avatar:<roster id>` (for example `avatar:alba`) or the name of an avatar in the workspace asset library. Leave it out unless the operator named one |
| `accentColor` | No | One of `orange`, `amber`, `yellow`, `lime`, `green`, `teal`, `cyan`, `sky`, `blue`, `indigo`, `violet`, `purple`, `pink`, `rose`, `slate` |
| `contextTokenLimit` | No | Token count, a digit string, or a percent such as `"75%"` |
| `contextCompressTargetTokens` | No | Same shapes as `contextTokenLimit` |
| `contextSelfEvictTokens` | No | Same shapes as `contextTokenLimit`. Empty means 80,000 tokens. When the packed prompt crosses it, the agent is told to evict the overflow |
| `contextMinRecentUserMessages` | No | Positive integer |
| `contextToolResultRounds` | No | Positive integer |
| `contextKgBodyTurns` | No | Positive integer |

Leave context keys out unless the operator asked for a custom context budget.

### Scopes

`chat`, `workflow` (AI node), `kg-extract` (Knowledge Graph extract), `eval` (eval judge), `icon`, `internal` (background worker, hidden from pickers).

A new package uses `chat` unless the operator named another surface. `icon` and `internal` are for workers Fontana calls itself.

An explicit `scopes` list contains at least one of those values.

### Abilities and skills

`abilities` is a mapping. The key is a built-in ability id. The value has `enabled` plus that ability's settings. An entry with `enabled: false` keeps its settings but grants nothing.

```yaml
abilities:
  knowledge-graph:
    enabled: true
  agents:
    enabled: true
    agents:
      - system/agents/fontana-agent
skills:
  - finance
```

An enabled ability's tools arrive when its package opens on a thread. `knowledge-graph` auto-loads on its own. Set `skillAutoLoad: { system/<id>: true }` only for the agent's primary job. An auto-loaded package costs its tools and instructions on every turn.

A conversational agent enables `agents` with `system/agents/fontana-agent` in `agents`, so Fontana product and navigation questions hand back to that agent. `agents: ["*"]` allows every active agent.

Enable only what the job needs. The operator can turn more on in the editor.

| Ability id | Settings you may set |
| --- | --- |
| `knowledge-graph` | `namespaces` (list of Knowledge Graph namespace names), `autoSearchKg` (boolean), `kbInjectionScoreThreshold` (number, platform default 0.35) |
| `agents` | `agents` (agent ids, or `*`) |
| `workflows` | `autoSearchWorkflows` (boolean). This ability is the Workspaces surface |
| `email` | `allowReceive`, `allowSend` (booleans), `receiveWhitelist`, `sendWhitelist` (lists of address patterns) |
| `messaging` | Slack. `messagingWhitelist` (channel names or ids), `slackInstallationId`, `toolSubset` |
| `teams` | `channelWhitelist`, `freeResponseChannels`, `requireMentionInThread`, `allowBots` |
| `coding` | `allowInternet` (boolean), `toolSubset` |
| `fontana-browser` | `toolSubset` |
| `files`, `data`, `system-one` | none |
| `mcp-<slug>` | `toolSubset`, for an MCP connection that already exists in the workspace |

Operator-authored skills are granted by namespace: `skills: [finance, acme]` lets the agent open every skill in those namespaces. The agent discovers them with `skills_listSkillsCatalog`, which runs for it on the first turn unless `autoDiscoverSkills: false`. Page skills (`dashboard-pages` and the other `*-pages` packages) belong to Fontana's own page agent and come with the `system` namespace. Leave that namespace off a specialist you are writing.

These frontmatter keys were replaced by the abilities above. A file that still contains one fails ingest: `tools`, `subagents`, `handoffAgents`, `knowledgeGraphNamespaces`, `autoSearchKg`, `autoSearchWorkflows`, `kbInjectionScoreThreshold`, `emailSendWhitelist`, `messagingWhitelist`. The avatar key is `icon`, not `avatar`.

Canvas editing stays on `system/agents/canvas-agent`. Hand that work off through the `agents` ability instead of granting the canvas skills to the package you are writing.

### Tool calls and MCP

You choose abilities. Fontana turns those into tool calls. Do not write a `tools` list in frontmatter.

A call id is either a built-in name (`email_send`) or an MCP name `mcp_<connection-slug>_<tool-name>`. Example: connection `knowledge-graph` and tool `kg_search` is `mcp_knowledge-graph_kg_search`. A trailing `.*` loads every tool that connection has discovered.

#### Calls every chat agent already has

These are present on every chat agent. Do not add them under `abilities`.

| Call | What it does |
| --- | --- |
| `system_renderUrl` | Show a link the person can open. It does not change the page until they click Open, and it does not browse the page. |
| `system_updateThreadTitle` | Set the chat thread title. |
| `system_createTaskTree` | Start a task list for this turn. |
| `system_addSubtasksUnderActiveTask` | Add subtasks under the task that is active now. |
| `system_addSubtasksUnderParent` | Add subtasks under a named open task. |
| `system_closeTask` | Close one task. Closing a parent cancels unfinished child tasks. |
| `system_compactThreadContext` | Fold older thread history into a summary. |
| `system_evictContext` | Drop stale tool results from later turns. A stub remains so the agent can fetch them again. |
| `system_wait` | Pause, then continue, when a page, a browser session, or other work is not ready yet. |
| `system_workspaceSecretsStatus` | Check which secrets are set in a workspace: name, when, and by whom. Never a value. |
| `system_requestWorkspaceSecret` | Ask the person to set a workspace secret through the Set secret dialog. The answer is the name and whether they set it. |
| `icon_generateIcon` | Draw a minimal SVG icon from a text prompt. |
| `skills_listSkillsCatalog` | List skills this agent may open, by namespace or `*`. Runs on the first turn when discovery is on. |
| `skills_activateSkill` | Turn a skill on for this turn. |
| `skills_closeSkill` | Turn that skill off. |
| `skills_readPackageFile` | Read a reference file of an active skill or of the agent's own package. |
| `hitl_askHuman` | Ask the person a structured question in chat. The answer comes back as an action plus values. |
| `agents_createSubAgentThread` | Open a side thread with an agent on the `agents` ability allow-list. |
| `agents_continueSubAgentThread` | Continue that side thread. |
| `agents_handoffThread` | Hand this thread to an agent on that allow-list. |
| `agents_delegateExternalAgent` | Ask a peer agent connected through Agent Interop. |

Delegation needs the `agents` ability with the target ids in `agents`. The four `agents_*` thread calls above are still always present; the allow-list decides who they may reach.

#### Calls an ability adds

Enable only the rows the job needs.

**`knowledge-graph`** (MCP connection `knowledge-graph`). Search stays inside `namespaces`. The last four calls in the table write the graph, and run only inside a Fontana agent turn. Use them only when the operator asked for extraction or curation.

| Call | What it does |
| --- | --- |
| `mcp_knowledge-graph_kg_search` | Hybrid search. Returns capped chunk packages (text, citation, section, mentions). |
| `mcp_knowledge-graph_kg_open` | Open packages by one of `chunkKey`, `outlineKey`, `entityKey`, or `fileId`. |
| `mcp_knowledge-graph_kg_hop` | Step to a neighbour: next or previous chunk, similar files, mentions, relations, same type, or outline child, parent, or siblings. |
| `mcp_knowledge-graph_kg_outline` | A file's section index. |
| `mcp_knowledge-graph_kg_ontology` | Published entity types and relation types for one namespace. |
| `mcp_knowledge-graph_kg_entity_search` | Find an entity by name. |
| `mcp_knowledge-graph_kg_file_entities` | Entities mentioned in one file. |
| `mcp_knowledge-graph_kg_file_triples` | Typed relations whose subject and object are both mentioned in one file. |
| `mcp_knowledge-graph_kg_namespaces` | Namespaces this caller may search. |
| `mcp_knowledge-graph_kg_collections` | Collections in a namespace, and the folders that belong to them. |
| `mcp_knowledge-graph_kg_files` | Find files by folder prefix, path glob, or content regex. |
| `mcp_knowledge-graph_kg_file` | Read one file: metadata, a text window, SQL on csv or tsv, or a JSON query. |
| `mcp_knowledge-graph_kg_cypher` | One read-only OpenCypher statement for an exact word, a figure, or a known path. At most 50 rows. A citation is the file path plus the chunk text. |
| `mcp_knowledge-graph_kg_upsert_triples` | Write instance triples, each citing its file and quote. |
| `mcp_knowledge-graph_kg_set_entity_types` | Set an entity's type. |
| `mcp_knowledge-graph_kg_propose_ontology_terms` | Propose entity types and relation patterns under the namespace's evolution policy. |
| `mcp_knowledge-graph_kg_merge_entities` | Merge two entities. A later merge does not undo it. |

**`files`** reads and writes Fontana Files.

| Call | What it does |
| --- | --- |
| `mcp_ffs_list_buckets` | List the namespaces this caller can read. |
| `mcp_ffs_create_bucket` | Create a namespace. The caller becomes its admin. |
| `mcp_ffs_list_files` | List the files under a folder. |
| `mcp_ffs_get_file` | Read a text file. |
| `mcp_ffs_query` | Query a file: a line window, grep, JSON, or SQL on csv or tsv. Keep it narrow. |
| `mcp_ffs_put_file` | Write a new version of a file. Read it in the same turn first. On a file Fontana reads, such as `AGENT.md` or `schedules.json`, the result says whether Fontana accepted it. |
| `mcp_ffs_rename_file` | Rename or move a file inside its namespace. |
| `mcp_ffs_delete_file` | Delete a file. |

**`data`** reads a workflow's configuration and run summary. Every call needs the workflow id from the operator, never a placeholder.

| Call | What it does |
| --- | --- |
| `data_queryWorkflow` | Read one part of the workflow configuration, or its run summary. |

The rows a run produced are files in the Project's namespace. Read them with the Fontana Files query tool, `mcp_ffs_query`, and keep the query narrow.

**`workflows`** is the Workspaces surface.

| Call | What it does |
| --- | --- |
| `workflow_searchWorkflows` | With no `query`, list the person's workflows newest first (`nameContains` narrows by title) to resolve one by name; with a `query`, find workflows and templates by meaning. `autoSearchWorkflows` runs the search on a new prompt. |
| `workflow_startWorkflowRun` | Start a run when the operator asked for one. |

A spec, notes or a report is a plain markdown file in the Workspace. Write and read it with the `files` calls, or in a terminal session with `coding`.

**`agents`** adds schedule calls on top of the delegation calls above. `agents` is who this agent may delegate to. Agent packages are Fontana Files files: read and edit them with the `files` calls. Who may change a package is decided by its namespace's grants alone.

| Call | What it does |
| --- | --- |
| `agents_listAgents` | Resolve a display name to an agent id. |
| `agents_upsertAgentEventSchedule` | Create or update an event schedule. It turns the schedule on for nobody; the result names the person's activation file. |
| `agents_triggerAgentSchedule` | Run a schedule now, named by the agent id and the schedule's `id` in that package's `schedules.json`. |

A schedule runs for a person only while they have turned it on. That is a file in their personal space in Fontana Files, `schedules/<agent id>/<schedule id>.yaml` holding `enabled: true`, which the agent writes with the `files` calls for the person it works for. The person can also turn it on with its switch on the agent's Schedules tab.

**`email`** is this agent's mailbox. Receive tools obey `receiveWhitelist`. `email_send` obeys `sendWhitelist`. An empty send list sends to nobody.

| Call | What it does |
| --- | --- |
| `email_listInbox` | List messages in the mailbox. |
| `email_search` | Search the mailbox. |
| `email_read` | Read one message, including its attachment list. |
| `email_draft` | Save a draft for a person to review. |
| `email_send` | Send. Every recipient must match the send whitelist. |

**`messaging`** is Slack (MCP connection `slack-channels`). Posts stay inside `messagingWhitelist`. `hitl_slackBlocks` is the Approve / Reject path. A plain post cannot carry that callback.

| Call | What it does |
| --- | --- |
| `mcp_slack-channels_list_installations` | List Slack installations. Other Slack calls need an installation id. |
| `mcp_slack-channels_list_conversations` | List channels and conversations the bot can see. |
| `mcp_slack-channels_get_conversation_history` | Read recent messages. The bot must already be in the channel. |
| `mcp_slack-channels_post_message` | Post or reply as the Fontana bot. |
| `mcp_slack-channels_list_users` | List people in the workspace. |
| `mcp_slack-channels_get_user` | Read one Slack profile. |
| `hitl_slackBlocks` | Ask for an Approve / Reject decision in Slack. |
| `voice_generateSpeech` | Speak a short answer aloud. |

**`teams`** is this agent's own Teams bot (MCP connection `teams-channels`). Turning the ability on creates the bot.

| Call | What it does |
| --- | --- |
| `mcp_teams-channels_list_installations` | List this tenant's Teams bots. |
| `mcp_teams-channels_post_message` | Post into a channel as this agent's bot. The app must already be installed in that team. |

**`coding`** is the agent's computer (ability card **Use a terminal session**, OpenSandbox connection `session`). In chat the agent calls it "my computer", for example "let me check on my computer". `mcp_session_open`, `mcp_session_exec`, and `mcp_session_close` run shell commands, scripts, and files there, with no network access. It does not see Fontana data unless the agent passes that data in, or opens with a named `bucket` and `writes` as a signed-in user. Files written there do not persist unless they were pushed. Set `allowInternet: true` to also grant `mcp_session_open_online`: that computer can reach the public internet on TCP 80 and 443 and includes curl and wget. Fetched pages and files are untrusted: they can carry instructions. Anything on the computer, including an attached bucket, can leave over the network. Live web pages are `fontana-browser`, which the agent calls "my browser".

**`fontana-browser`** is the agent's browser for live pages. In chat the agent calls it "my browser", for example "let me open this page on my browser". Shell, files, and scripts are `coding`. The same tools exist on connections `fontana-browser` and `steel`. Prefer the `mcp_fontana-browser_` ids. Leave `toolSubset` empty unless the operator named a subset. `steel_scrape`, `steel_screenshot`, and `steel_pdf` do not start a browser session. The session tools do.

| Call | What it does |
| --- | --- |
| `mcp_fontana-browser_steel_scrape` | Read a page as markdown or HTML. |
| `mcp_fontana-browser_steel_screenshot` | Capture a screenshot of a page. |
| `mcp_fontana-browser_steel_pdf` | Render a page to PDF. |
| `mcp_fontana-browser_steel_session_options` | Plan a session before creating one. |
| `mcp_fontana-browser_steel_session_create` | Start a browser session. |
| `mcp_fontana-browser_steel_navigate` | Open a URL in that session. |
| `mcp_fontana-browser_steel_snapshot` | Read the current page as a tree of elements the next call can act on. |
| `mcp_fontana-browser_steel_find` | Find one element on the current page. |
| `mcp_fontana-browser_steel_act` | Click, type, select, scroll, or press a key. |
| `mcp_fontana-browser_steel_wait_for` | Wait until text, a selector, or a URL is present. |
| `mcp_fontana-browser_steel_batch` | Run several reversible steps in one call. |
| `mcp_fontana-browser_steel_session_diagnostics` | Read activity from a live or finished session. |
| `mcp_fontana-browser_steel_session_handoff` | Let the person drive the live session, then resume. |
| `mcp_fontana-browser_steel_session_replay` | Return a replay link for a finished session. |
| `mcp_fontana-browser_steel_session_live_view` | Connection details for the on-screen preview. The model does not receive page content from this call. |
| `mcp_fontana-browser_steel_session_release` | End the session. |

**Memory** needs no ability. Every agent has these two calls. Do not add a memory entry under `abilities`. Memories are private to the person the agent runs for and shared by the agents that person runs.

| Call | What it does |
| --- | --- |
| `knowledge_addMemory` | Remember a preference, decision, or correction. |
| `knowledge_forgetMemory` | Remove a memory the person retracted. |

**`system-one`** asks TypeSafe System One for one calibrated decision.

| Call | What it does |
| --- | --- |
| `systemone_ask` | Ask one typed question. Returns a decision and a confidence. Report both as returned. |

#### MCP the operator already connected

Seeded connections are the abilities above. Do not also enable `mcp-<slug>` for these slugs: `knowledge-graph`, `ffs`, `slack-channels`, `teams-channels`, `session`, `steel`, `fontana-browser`.

Any other connection the operator created on **AI → Tools** is `mcp-<slug>`, where `<slug>` is that connection's slug. `enabled: true` loads every tool the connection has discovered, as `mcp_<slug>_<tool-name>`. `toolSubset` is a list of those ids when the operator wants fewer.

Use the slug and the tool names the operator gave you. Do not invent either. If they did not name a connection, leave `mcp-*` off the package.

`toolSubset` on Slack, Computer, and Fontana Browser is a list of `mcp_<connection>_<tool>` ids. Omit it to load the whole connection. Teams has no `toolSubset`.

Page skills (`dashboard-pages`, `skills-admin`, `mcp-admin`, and the other `*-pages` packages) belong to Fontana agent through the `system` namespace. Leave that namespace off the package you are writing. `mcp-admin` is how Fontana agent registers a connection. It is not how you attach one.

### Permissions

`permissions: ["*"]` allows every catalog permission. At runtime the usable set is the invoking person's role overlapped with this list. Narrower entries are ids such as `knowledge-graph:read` or a resource wildcard such as `workflows.*`.

### Call settings

A mapping, or `{}`. Runtime reads these keys only: `temperature`, `maxOutputTokens`, `topP`, `topK`, `presencePenalty`, `frequencyPenalty`, `stopSequences`, `seed`. Use `temperature: 0` for analytical work unless the operator asked otherwise.

### System prompt body

Write a specialist brief, in Markdown, after the frontmatter:

1. **Role:** expertise, tone, and the hard limits a legal, medical, or financial domain needs
2. **Context:** who it serves, typical assignments, when to escalate
3. **Core responsibilities:** verb-led
4. **Operating principles:** how it separates fact, interpretation, and recommendation
5. **Workflow:** intake, analysis, delivery, self-check
6. **Output format:** the markdown skeleton to return
7. **Quality bar:** checks before it finishes
8. **Handoff:** when to hand Fontana product questions to `system/agents/fontana-agent`

Keep platform mechanics out of the body (thread compaction, knowledge-graph injection, delegate tables). The runtime adds those when the abilities are enabled.

`description` and `vectorSource` stay about the domain, not about Fontana Agent itself.

## schedules.json

Optional. When you include it, the document has one key, `schedules`, and each entry has `id`, `name`, `prompt`, and `schedule`. Ids are unique inside the file.

Cron uses `expr` (UTC), never a field named `cron`:

```json
{
  "schedules": [
    {
      "id": "daily-digest",
      "name": "Daily digest",
      "prompt": "Summarise overnight activity.",
      "schedule": { "kind": "cron", "expr": "0 8 * * *" }
    }
  ]
}
```

Workflow events set `kind` to `"event"`, `event` to one of `workflow_run_completed`, `workflow_run_failed`, `workflow_run_succeeded`, `exception_raised`, `exception_status_changed`, and `workflowId` to the operator's workflow id. `email_received` omits `workflowId`. `{ "kind": "manual" }` never runs on a timer.

Omit `schedules.json` when the operator did not ask for a schedule. They can add one later in the Agents editor.

## Example package

`nav-analyst/AGENT.md`:

```md
---
title: NAV Analyst
role: NAV analyst
description: Reviews NAV packs and explains breaks in plain language for the fund accounting team.
vectorSource: NAV analyst net asset value breaks reconciliation
model: ""
scopes:
  - chat
abilities:
  knowledge-graph:
    enabled: true
  agents:
    enabled: true
    agents:
      - system/agents/fontana-agent
isActive: true
permissions:
  - "*"
reasoningEffort: high
callSettings:
  temperature: 0
---

## Role

You are a NAV analyst for the fund accounting team. You explain breaks in plain language. Sign-off and investment advice stay with the team.

## Context

You serve accountants who upload a pack or name a fund and a date. When the request is about Fontana itself (where to click, how agents work), hand off to `system/agents/fontana-agent`.

## Core responsibilities

- Restate the fund, date, and question before you analyse.
- Separate figures you were given from calculations you made.
- Name the source section for every figure you cite.

## Workflow

1. Confirm fund, date, and the question.
2. Use enabled Knowledge Graph namespaces when the pack is already filed there.
3. Deliver the skeleton below.
4. Check that every number traces to a source you were given.

## Output format

- **Question**
- **Findings**
- **Sources**
- **Open items**

## Handoff

Hand Fontana product and navigation questions to `system/agents/fontana-agent`.
```

## Before you finish

Confirm all of the following, then tell the operator the folder name, the `title`, and the upload path.

- The directory contains `AGENT.md` directly inside it.
- Frontmatter has `title`, `description`, and `vectorSource`, and the body is a real system prompt.
- Frontmatter omits `id`, `name`, and `avatar`.
- `abilities` keys are ability ids with `enabled`; settings match the table above. `skills`, when present, lists namespaces.
- `scopes`, when present, lists only the values in this skill.
- `icon`, when present, is an asset reference such as `avatar:alba`, never a file path or SVG markup.
- `schedules.json`, when present, is one JSON object with a `schedules` array, and cron triggers use `expr`.

## Upload

1. Open **AI → Agent packages** (`/ai/agents`).
2. Select the `agents/` folder of a namespace the operator created.
3. Choose **Upload folder** and select the package directory.
4. Open the imported package and confirm the title, abilities, and prompt. If a file cannot be parsed, the error shows on the agent page; fix the file and save it again.
