> ## Documentation Index
> Fetch the complete documentation index at: https://sdk.ekanos.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate an existing agent framework

> Move agents defined as AGENT.md, agent.yaml, policy files and skill folders onto Ekanos managed agents: what maps to agent.json, the steps, and what does not carry over yet.

Many teams already define their agents in files: an `AGENT.md` with the instructions, an `agent.yaml` with the model and tools, policy files that say what needs a person, and a folder of skills. A managed agent in Ekanos is the same idea held as data, so most of it moves across directly. This guide maps each piece, then lists what doesn't map yet.

You need a seat on the Source: `developer` to store drafts, `source_admin` to push skills, test and publish. Read [Sources, team accounts and integrations](https://sdk.ekanos.dev/concepts/sources-and-teams.md) first if those words are new to you.

## The target layout

```
agents/
  support-triage/
    agent.json          # what the agent is: model, tools, policy, skills, connections
    AGENT.md            # the instructions
    skills/
      refund-policy/
        SKILL.md
```

`agent.json` and `AGENT.md` are what `ekanos agents pull` writes and `ekanos agents apply` reads. Every field and its limits are in the [commands reference](https://sdk.ekanos.dev/cli/commands.md#agents). Unknown fields are refused, so leave anything that doesn't map out of the file rather than carrying it along.

## How the pieces map

| In your framework | In Ekanos | Notes |
| - | - | - |
| `AGENT.md`, system prompt | `AGENT.md`, or `instructions` in `agent.json` | Up to 20,000 characters. `AGENT.md` is used when `agent.json` has no `instructions`. |
| Name and description | `name` (up to 80), `description` (up to 500) | |
| Model | `model` | A model ID your Source has, or `null` for the default. `apply` refuses a model the Source doesn't know. |
| Max steps or iterations | `maxTurns` | 1 to 100, default 50. |
| Tool allowlist | `tools` | `read_only` (every read on the products it can reach), `all`, or `custom` with whole `products` and single `tools`, named as `ekanos catalog` lists them. |
| Tool denylist | Leave the tool out of `tools` | There is no deny list. A tool that isn't granted can't be called. |
| "Needs human approval" rules | `policy` | `reads` and `writes` set the default for each effect, `auto` or `approve`. `overrides` set single tools by name. |
| Credentials, API keys, OAuth config | `connections` | Never in a file. Each team connects its own account in the app; `connections` says whether it's `required` or `optional`. |
| MCP servers | `mcpServers` | Remote servers over HTTPS, up to 10, with `auth` of `none`, `bearer` or `oauth`. `toolEffects` says which tools only read; anything unlisted counts as a write. |
| Skills folder | `skills/<slug>/SKILL.md` next to `agent.json` | `agents apply` pushes each folder and names it in `skills`. See [Skills](#skills). |
| Per-team variations | `teamCustomization` | What a team may add on top: its own skills, MCP servers or integrations, or stricter limits (`narrow`). All off by default. |
| Triggers (schedules, webhooks, events) | Set on each team | Not in `agent.json` yet. See [Triggers and links](#triggers-and-links). |
| Sub-agents, hand-offs, agent-to-agent calls | Separate agents plus links | Each sub-agent becomes its own agent. Links are set on each team. |

### Policy

Most frameworks express approval as rules per tool. In Ekanos every granted tool resolves to one of two answers: `auto` runs on its own, `approve` waits for a person in the app.

```json theme={null}
"policy": {
  "reads": "auto",
  "writes": "approve",
  "overrides": {
    "zendesk_add_internal_note": "auto",
    "mcp__docs__search": "auto"
  }
}
```

* Start from `reads: auto`, `writes: approve`, then add an `auto` override for each write you're happy to let run, such as an internal note.
* A tool's effect comes from its integration. An MCP tool you haven't marked as a read in `toolEffects` counts as a write, so it waits under `writes: approve`.
* MCP tools are named `mcp__<server key>__<tool>` in `overrides`.

### MCP servers

```json theme={null}
"mcpServers": [
  {
    "key": "docs",
    "name": "Product docs",
    "url": "https://docs.example.com/mcp",
    "auth": "none",
    "owner": "team",
    "team": "required",
    "toolEffects": { "search": "read" }
  }
]
```

When a team turns the agent on, a team-owned server is added to that team. With `auth: "none"` it works straight away; otherwise the team signs in. Teams can't change the effects you declared.

### Skills

A skill is a folder in the same format Claude Code uses: `SKILL.md` with `name` and `description` frontmatter, plus optional `references/` and `assets/`. Copy each of your skill folders to `agents/<key>/skills/<slug>/`.

```markdown theme={null}
---
name: refund-policy
description: How we decide refunds. Use when a customer asks for money back.
---

# Refund policy

...
```

`ekanos agents apply agents/<key>` pushes each folder as a Source skill first, then names it in the agent's `skills`. Pushing needs a Source admin; with a `developer` seat, pass `--no-skills` and ask a Source admin to run `ekanos skills push <dir>`. A skill only one team should see is pushed with `--team <slug>`.

The whole folder reaches the agent: it loads `SKILL.md` and opens the other files (`references/`, `assets/`) when the instructions point to them. Before you copy skills across, read [the gaps](#gaps): executable skills don't carry over.

### Triggers and links

Triggers and links can live in the template, so every team gets them: `agent.json`'s `triggers` and `links`, or `ekanos agents triggers <key> add …` and `ekanos agents links <key> add …`, published like any change. Where the template's `teamOverrides` lets teams change them, a team adds its own on the agent's **Triggers** tab, or a Source admin does from the terminal:

```bash theme={null}
ekanos teams triggers add qa-team support-triage event zendesk.ticket_created --filter '{"tags":["billing"]}' --source acme
ekanos teams triggers add qa-team feedback-agent event linear.issue_labeled --filter '{"labels":["feedback"]}' --source acme
ekanos teams triggers add qa-team support-triage schedule --cron "0 9 * * 1-5" --timezone America/Los_Angeles --prompt "Summarize yesterday's escalations." --source acme
ekanos teams links add qa-team support-triage billing-specialist --kind delegate --mode await --source acme
```

A **talk** link lets one agent ask another a question and wait for the answer; the asked agent can only read. A **delegate** link hands over a task: with `--mode await` the caller waits for the result, which is the orchestrator pattern, and with `--mode handoff` it carries on and the other agent owns the outcome. A delegated agent runs with its own tools and policy, never the caller's.

Map each old trigger onto the event it actually listened for. `ekanos catalog <product> --source acme --json` lists every event a product declares under `agentEvents`, with its filter keys: Linear has `linear.mentioned`, `linear.assigned`, `linear.issue_labeled` and `linear.issue_created`; Zendesk has `zendesk.ticket_created` and `zendesk.comment_added`. A label-driven agent stays label-driven (`linear.issue_labeled`); it does not have to become an @mention.

Slack triggers, and the **Linear (Agents app)** trigger (Ekanos's own Linear app, which answers @mentions and labelled issues), belong to each team rather than the template: install with `ekanos teams connect <team> slack|linear-app`, then `ekanos teams triggers add <team> <key> slack --channel '#support' --yes` or `… linear [--label <name>]`, or use the agent's **Triggers** tab in the app. The Linear integration's events above are added from the terminal like any other event.

> [!NOTE]
>
> Coming: `triggers`, `links` and `teamOverrides` in `agent.json`, so the
> template sets them for every team, and `ekanos agents
>     policy|triggers|links|overrides <key>` to edit them on the draft. Until that
> ships, set them per team as above.

## Steps

1. **Set up a folder.**

   ```bash theme={null}
   mkdir agents && cd agents
   npx @ekanos/cli login --host https://your-ekanos-host
   npx @ekanos/cli agents init
   ```

   `agents init` adds the skills and docs server Claude Code uses to build agents. If you'd rather have Claude do the mapping, open `claude` in the folder, point it at your old repository and ask it to migrate one agent. It follows the same table.

2. **Check what the Source has.** `ekanos catalog --source acme --json` lists each product's tools by the names `tools` and `policy` use, and the events triggers can start from. A tool your old agent called that isn't in the catalog is a [gap](#gaps).

3. **Write the files.** One agent per folder, starting with the simplest one. Move the instructions to `AGENT.md`, and build `agent.json` from the table above.

4. **Store a draft.**

   ```bash theme={null}
   ekanos agents apply agents/support-triage --source acme
   ekanos agents show support-triage --source acme
   ```

   `apply` checks every product, tool, skill and model against the Source and names each field it refuses, such as `tools.tools.0`. Nothing reaches a team yet.

5. **Publish the first version, then test on one team.** A team can only turn on an agent that has been published once, and publishing alone changes nothing for a team until it turns the agent on. Turn it on for a test team, then run it:

   ```bash theme={null}
   ekanos agents publish support-triage --source acme --yes
   ekanos teams agents enable qa-team support-triage --source acme
   ekanos agents test support-triage --team qa-team --prompt "A new ticket asks for a refund." --follow
   ```

   For every change after that, `agents test` runs your unpublished draft on the test team. See [Test an agent before you publish](https://sdk.ekanos.dev/guides/test-agents.md).

6. **Roll it out.** Publish each tested version. Every team that follows the latest version moves to it; `ekanos agents rollback <key> --to <n> --yes` takes them back.

## Gaps

What doesn't carry over today, and what to do instead:

* **Tools written as code.** An agent can only call tools that a Source product or an MCP server provides. A function your framework ran in-process has to become an integration built with the [SDK](https://sdk.ekanos.dev/sdk/overview.md), or live behind a remote MCP server.
* **Local MCP servers.** Only remote servers over HTTPS are supported. A server you ran over stdio needs to be hosted.
* **Conditional approval rules.** Policy is `auto` or `approve` per tool. A rule that looks at arguments, such as "approve refunds over \$100", doesn't map; choose `approve` for the tool, or split the action into two tools in an integration.
* **Binary skill files.** The agent reads every text file in a skill's folder, but an image or a PDF under `assets/` is only listed, not read. Put what it must know in a text file.
* **Executable skills.** A skill with a `scripts/` folder is refused. Skills are limited to 100 files, 1 MB per file and 3 MB per skill.
* **Skill versions.** A skill push is live at once, for every agent that names the skill, on its next run. It doesn't go through apply, test and publish, so review a skill change as carefully as a publish.
* **Slack and the Ekanos Agents app for Linear in the template.** Their triggers are per team (`ekanos teams triggers add … slack|linear`, or the app), because each team installs its own workspace and picks its channels. Every integration event, including all of Linear's and Zendesk's, can be in the template or per team.
* **One shared connection for every team.** `owner: "source"` in `connections` works for integrations that declare a Source connection, such as Zendesk: the Source admin connects once (`ekanos apps connect`) and maps events to teams (`ekanos routes`). It is refused for other integrations and for `mcpServers`.
* **Secrets in config.** No secret goes in `agent.json`, a flag or a file. Teams enter theirs in the app, and a Source admin enters an app secret at an interactive terminal.

See also: [Build agents with Claude](https://sdk.ekanos.dev/guides/managed-agents.md), [Commands reference](https://sdk.ekanos.dev/cli/commands.md#agents).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.