@ekanos/cli 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +1 -0
  2. package/dist/commands/agents-edit.d.ts +49 -0
  3. package/dist/commands/agents-edit.js +385 -0
  4. package/dist/commands/agents-edit.js.map +1 -0
  5. package/dist/commands/agents.d.ts +24 -1
  6. package/dist/commands/agents.js +117 -8
  7. package/dist/commands/agents.js.map +1 -1
  8. package/dist/commands/apps.d.ts +6 -2
  9. package/dist/commands/apps.js +249 -4
  10. package/dist/commands/apps.js.map +1 -1
  11. package/dist/commands/reviewers.d.ts +21 -0
  12. package/dist/commands/reviewers.js +162 -0
  13. package/dist/commands/reviewers.js.map +1 -0
  14. package/dist/commands/routes.d.ts +23 -0
  15. package/dist/commands/routes.js +277 -0
  16. package/dist/commands/routes.js.map +1 -0
  17. package/dist/commands/runs.d.ts +42 -0
  18. package/dist/commands/runs.js +362 -0
  19. package/dist/commands/runs.js.map +1 -0
  20. package/dist/commands/skills.d.ts +60 -0
  21. package/dist/commands/skills.js +397 -0
  22. package/dist/commands/skills.js.map +1 -0
  23. package/dist/commands/team-agents-agents.d.ts +9 -0
  24. package/dist/commands/team-agents-agents.js +188 -0
  25. package/dist/commands/team-agents-agents.js.map +1 -0
  26. package/dist/commands/team-agents-mcp.d.ts +4 -0
  27. package/dist/commands/team-agents-mcp.js +218 -0
  28. package/dist/commands/team-agents-mcp.js.map +1 -0
  29. package/dist/commands/team-agents-triggers.d.ts +12 -0
  30. package/dist/commands/team-agents-triggers.js +251 -0
  31. package/dist/commands/team-agents-triggers.js.map +1 -0
  32. package/dist/commands/team-agents.d.ts +31 -0
  33. package/dist/commands/team-agents.js +71 -0
  34. package/dist/commands/team-agents.js.map +1 -0
  35. package/dist/commands/teams-onboard.d.ts +51 -0
  36. package/dist/commands/teams-onboard.js +261 -0
  37. package/dist/commands/teams-onboard.js.map +1 -0
  38. package/dist/commands/teams.d.ts +16 -1
  39. package/dist/commands/teams.js +22 -3
  40. package/dist/commands/teams.js.map +1 -1
  41. package/dist/connections-api.d.ts +125 -0
  42. package/dist/connections-api.js +156 -0
  43. package/dist/connections-api.js.map +1 -0
  44. package/dist/index.js +226 -6
  45. package/dist/index.js.map +1 -1
  46. package/dist/reviewers-api.d.ts +33 -0
  47. package/dist/reviewers-api.js +81 -0
  48. package/dist/reviewers-api.js.map +1 -0
  49. package/dist/routes-api.d.ts +105 -0
  50. package/dist/routes-api.js +147 -0
  51. package/dist/routes-api.js.map +1 -0
  52. package/dist/runs-api.d.ts +34 -0
  53. package/dist/runs-api.js +112 -0
  54. package/dist/runs-api.js.map +1 -0
  55. package/dist/skills-api.d.ts +28 -0
  56. package/dist/skills-api.js +104 -0
  57. package/dist/skills-api.js.map +1 -0
  58. package/dist/teams-api.d.ts +45 -3
  59. package/dist/teams-api.js +72 -3
  60. package/dist/teams-api.js.map +1 -1
  61. package/package.json +2 -2
  62. package/templates/package.json.tmpl +4 -4
  63. package/templates/skills/build-agent/SKILL.md +94 -10
  64. package/templates/skills/build-agent/references/agent-json.md +85 -4
  65. package/templates/skills/build-agent/references/rollout.md +9 -1
  66. package/templates/skills/build-agent/references/set-up-an-integration.md +59 -3
  67. package/templates/skills/build-agent/references/skills.md +81 -0
  68. package/templates/skills/build-agent/references/triggers.md +25 -5
  69. package/templates/skills/ekanos-platform/SKILL.md +116 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekanos/cli",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "private": false,
5
5
  "description": "The Ekanos partner toolchain CLI: scaffold, validate, and test an Ekanos integration against the published @ekanos packages. Agent-native — every verb speaks JSON with a stable exit-code taxonomy.",
6
6
  "keywords": [
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@clack/prompts": "1.7.0",
38
- "@ekanos/integration-schema": "0.13.0",
38
+ "@ekanos/integration-schema": "0.15.0",
39
39
  "esbuild": "0.28.1",
40
40
  "picocolors": "1.1.1"
41
41
  },
@@ -12,12 +12,12 @@
12
12
  "prepare": "node scripts/setup-hooks.mjs"
13
13
  },
14
14
  "dependencies": {
15
- "@ekanos/sdk": "^0.13.0",
16
- "@ekanos/ui": "^0.13.0"
15
+ "@ekanos/sdk": "^0.15.0",
16
+ "@ekanos/ui": "^0.15.0"
17
17
  },
18
18
  "devDependencies": {
19
- "@ekanos/cli": "^0.10.0",
20
- "@ekanos/harness": "^0.7.4",
19
+ "@ekanos/cli": "^0.12.0",
20
+ "@ekanos/harness": "^0.15.0",
21
21
  "@hookform/resolvers": "^5.2.2",
22
22
  "@tailwindcss/postcss": "^4.3.3",
23
23
  "@tanstack/react-query": "^5.101.4",
@@ -68,7 +68,12 @@ through it? It takes about ten minutes." Then follow
68
68
  `references/set-up-an-integration.md`. It covers where the connection should
69
69
  live (each team through the Source's app, each team with its own app, or one
70
70
  for the whole Source), the integration's own steps, one per message, and
71
- checking each one with `ekanos teams show` before moving on. For the
71
+ checking each one with `ekanos teams show` before moving on. If the team
72
+ itself does not exist yet, create it and invite its people first
73
+ (`ekanos teams create`, `ekanos teams members invite`, `ekanos teams roles
74
+ list` to find the role holding `agents.review` for reviewers — see the
75
+ `ekanos-platform` skill, "Onboarding a team"), and send the member who will
76
+ sign in the link from `ekanos teams connect <team> <product>`. For the
72
77
  Source's app itself, `references/app-setup.md` has the console walk-through.
73
78
  Secrets are only ever entered at the user's terminal or in the app.
74
79
 
@@ -88,20 +93,29 @@ in parentheses are the recommendation when the user has no preference.
88
93
  (Reads only to start; add writes once it has earned trust.)
89
94
  4. **What waits for a person.** Reads run on their own, changes wait for
90
95
  approval — and any per-tool exceptions (a public reply to a customer
91
- almost always waits). See `references/agent-json.md` → `policy`.
96
+ almost always waits). See `references/agent-json.md` → `policy`. If
97
+ anything waits, ask who decides it — see **Reviewers** below.
92
98
  5. **Whose connections.** For each product and MCP server, where the
93
99
  connection lives (`references/set-up-an-integration.md` § 2): each team
94
100
  connects its own, and it is `required` (the agent waits at "needs setup"
95
101
  until the team connects it) or `optional` (its tools appear once
96
- connected). One connection shared by every team is not available yet;
97
- say so if they ask for it. Then offer to set up any that are not ready.
102
+ connected). Or, for integrations that support it, the Source connects it
103
+ once for every team (`owner: "source"`): each team's agent then works only
104
+ inside what is routed to that team (`references/set-up-an-integration.md`
105
+ § 5). Then offer to set up any that are not ready.
98
106
  6. **What teams may add** — their own MCP servers, their own skills, more of
99
107
  their own integrations, or narrowing (removing tools, more approvals). All
100
108
  off unless there is a reason. Give one concrete example per knob.
101
- 7. **What starts it** — see `references/triggers.md`. Triggers belong to each
102
- team and are set after turning the agent on; say what each team will have
103
- to set up (an @mention, a label, a new ticket, a schedule) and what it
104
- needs connected first.
109
+ 7. **What starts it** — see `references/triggers.md`. Declare the triggers in
110
+ the template (an event such as `zendesk.ticket_created` with its filters,
111
+ a schedule, a webhook) so every team gets them, or leave them to each
112
+ team. Say what each team needs connected first.
113
+ 8. **Who it works with** — other agents of this Source it may ask or hand
114
+ work to (`links`). A link only exists in a team that runs both agents.
115
+ 9. **What teams may change** — `teamOverrides` per area (approvals,
116
+ triggers, links). Off (the default) means teams follow the template
117
+ exactly; on lets a team keep its own differences. Switching an area off
118
+ later keeps a team's differences but stops applying them.
105
119
 
106
120
  ## 3. Draft, apply, publish
107
121
 
@@ -111,21 +125,91 @@ in parentheses are the recommendation when the user has no preference.
111
125
  The instructions say: the job, the sources of truth and when to consult
112
126
  each, what to do when unsure (ask, or hand to a person), tone, and what
113
127
  never to do. Show the user both files and walk through them.
128
+ Know-how the agent loads only when needed (a policy, a playbook) goes in
129
+ a skill folder, `agents/<key>/skills/<slug>/SKILL.md` — see
130
+ `references/skills.md`. Content only one team may see is a **team
131
+ skill**: `ekanos skills push <dir> --team <team-slug>`.
114
132
  2. On their go: `npx @ekanos/cli agents apply agents/<key> --source <slug> --json`.
115
133
  A refusal (exit 3) lists each problem with its path in the body — explain
116
134
  and fix them together. The stored version is a **draft**: no team sees it.
135
+ Skill folders beside the agent are pushed first and are **live at once**
136
+ (unlike the agent) — say so before applying, and show the user what
137
+ `skills` the output reports as created or changed.
117
138
  3. `npx @ekanos/cli agents show <key> --source <slug>` — review the stored draft
118
139
  with the user.
140
+ Then test it on one team that has turned the agent on, without publishing:
141
+ `npx @ekanos/cli agents test <key> --team <team> --prompt "…" --follow --json`
142
+ (or `--input example.json` for a real ticket or event). It runs the latest
143
+ version on that team as a test run — same tools, approvals and audit; the
144
+ team's current agent still bounds what it may do, so a draft can only do
145
+ less. A write waits for an approval like any run (see "Running, watching
146
+ and deciding" below).
119
147
  4. Ask: publish this version to every team now? Only on yes:
120
148
  `npx @ekanos/cli agents publish <key> --source <slug> --to <n> --yes`.
121
- 5. Hand over the team-side checklist (`references/triggers.md` has the
149
+ 5. If anything waits for approval, name its reviewers (**Reviewers**
150
+ below) before teams turn it on — a draft nobody may decide just waits.
151
+ 6. Hand over the team-side checklist (`references/triggers.md` has the
122
152
  per-integration parts): find it under Agents → "Provided for your team",
123
153
  Turn on, connect what it needs, confirm access, add triggers. Suggest one
124
154
  team pilots it first, and plan a first test run with them.
125
155
 
156
+ ## Reviewers
157
+
158
+ Reply drafts held under an `approve` policy are decided by the team's own
159
+ managers (`agents.manage`) and reviewers (`agents.review`), and — for agents
160
+ the Source provides — by the Source's **named reviewers**. A Source admin
161
+ names them; each must be a member of one of the Source's teams, and is
162
+ notified of every draft in their reach.
163
+
164
+ - `npx @ekanos/cli reviewers list --source <slug> --json` — who reviews now.
165
+ - `npx @ekanos/cli reviewers add <email> --reach source --source <slug>` —
166
+ decides drafts from every team's provided agents, in the Source's review
167
+ queue at `/reviews` (reviewers are managed at `/management/reviewers`).
168
+ - `npx @ekanos/cli reviewers add <email> --reach team --team <team-slug> --source <slug>`
169
+ — decides one team's drafts, from the same review queue (they need not be
170
+ a member of that team).
171
+ - `npx @ekanos/cli reviewers remove <email> [--team <team-slug>] --source <slug>`
172
+ — every reach, or just that team's.
173
+
174
+ The first decision settles a draft for everyone. Recommend one or two
175
+ source-reach reviewers for an agent provided to every team, plus team-reach
176
+ reviewers where a team wants its own people deciding. A refusal with
177
+ `USER_NOT_IN_SOURCE` means the person is not on any of the Source's teams yet.
178
+
126
179
  ## Changing it later
127
180
 
128
181
  `npx @ekanos/cli agents pull <key> --source <slug>` writes the latest version to
129
182
  `agents/<key>/`; edit, `apply` (a new draft), `show`, then `publish` on the
130
- user's yes. `rollback <key> --to <n> --yes` republishes an earlier version.
183
+ user's yes. For one small change, edit the stored draft directly — `agents
184
+ policy <key> set <tool> approve`, `agents triggers <key> add|remove …`,
185
+ `agents links <key> add|remove …`, `agents overrides <key> enable|disable
186
+ <area>` (each stores a new draft; see `references/agent-json.md` § Editing
187
+ one area without a file) — then `publish` on the user's yes. `rollback <key> --to <n> --yes` republishes an earlier version.
131
188
  Teams that pinned a version stay on it and are told a newer one exists.
189
+
190
+ ## Running, watching and deciding
191
+
192
+ All as the Source admin, on one team (`--team <slug>`; `ekanos teams list`
193
+ names them). Add `--json` for a stable record a script can assert on.
194
+
195
+ - `npx @ekanos/cli runs start <key> --team <team> --prompt "…" [--follow]` —
196
+ the app's "Run now": runs as the agent's owner under its own tools and
197
+ approvals, recorded as started by you. `--input <file.json>` passes a
198
+ payload instead of (or beside) the prompt. `--follow` prints status,
199
+ messages and each tool call until the run ends or waits on an approval.
200
+ - `npx @ekanos/cli runs list --team <team> [--agent <key>]` — recent runs.
201
+ - `npx @ekanos/cli runs show <run-id> --team <team> --json` — trigger, version
202
+ (and `draftTemplateVersion` on a test run), output, transcript, every tool
203
+ call with `authorizedVia` (`auto` or `approved`), and its approvals. A leak
204
+ test is a script over this: e.g. assert no `transcript` tool result and no
205
+ `output` contains a value the agent must never reveal.
206
+ - `npx @ekanos/cli approvals list --team <team>` — what is waiting.
207
+ - `npx @ekanos/cli approvals approve <id> --team <team> [--reason "…"]` /
208
+ `approvals reject <id> --team <team> --reason "…"` — decided as you, with
209
+ the authority a team's agent manager has in the app.
210
+ - `npx @ekanos/cli approvals edit <id> --team <team> --body ./reply.md` — Edit &
211
+ send a reply draft: approves it with your text instead. Only reply drafts
212
+ take an edit.
213
+
214
+ Never approve on the user's behalf without asking: show them what the agent
215
+ proposes (`approvals list`) and decide only on their word.
@@ -33,7 +33,25 @@ conflicting change unless `--overwrite`. Unknown fields are refused.
33
33
  "toolEffects": { "search": "read" }
34
34
  }
35
35
  ],
36
- "teamCustomization": { "mcpServers": false, "skills": false, "integrations": false, "narrow": false }
36
+ "teamCustomization": { "mcpServers": false, "skills": false, "integrations": false, "narrow": false },
37
+ "triggers": [
38
+ {
39
+ "key": "new-tickets",
40
+ "type": "event",
41
+ "event": "zendesk.ticket_created",
42
+ "filter": { "tags": ["vip", "urgent"], "brand": "123", "reply_as": "internal_note" }
43
+ },
44
+ {
45
+ "key": "weekday-digest",
46
+ "type": "schedule",
47
+ "cron": "0 9 * * 1-5",
48
+ "timezone": "America/Los_Angeles",
49
+ "prompt": "Summarize yesterday's open escalations."
50
+ },
51
+ { "key": "inbound", "type": "webhook", "prompt": "Triage the posted ticket." }
52
+ ],
53
+ "links": [{ "to": "billing-agent", "kind": "delegate", "mode": "handoff" }],
54
+ "teamOverrides": { "policy": false, "triggers": true, "links": false }
37
55
  }
38
56
  ```
39
57
 
@@ -58,10 +76,17 @@ The tool names above are illustrations. Take real ones from
58
76
  defaults by the tool's effect; `overrides` set single tools by name. An
59
77
  undeclared tool effect counts as a write. MCP tools are named
60
78
  `mcp__<server key>__<tool>` in `overrides`.
61
- - **`skills`** — skill slugs the Source or the platform already has.
79
+ - **`skills`** — skill slugs the Source or the platform already has. Skill
80
+ folders in `agents/<key>/skills/<slug>/` are pushed and added here by
81
+ `agents apply` (see `skills.md`).
62
82
  - **`connections`** — by product slug: `{ "owner": "team", "team": "required" | "optional" }`.
63
- A product with no entry is `team`/`optional`. `owner: "source"` (one
64
- connection for every team) is refused today.
83
+ A product with no entry is `team`/`optional`. `{ "owner": "source" }` is
84
+ one connection the Source admin makes for every team (`ekanos apps
85
+ connect`), used only by this provided agent and limited per team by the
86
+ Source's routing (`ekanos routes`); `apply` refuses it for an integration
87
+ that does not declare `sourceConnection`. Teams cannot add a Source-owned
88
+ product in their overlay. `mcpServers` with `owner: "source"` are still
89
+ refused.
65
90
  - **`mcpServers`** — remote MCP servers (streamable HTTP, `https` only, up to
66
91
  10): `key` (lowercase, ≤31), `name`, `url`, `auth` (`none` | `bearer` |
67
92
  `oauth`, default `oauth`), `owner`/`team` as for connections, and
@@ -77,6 +102,62 @@ The tool names above are illustrations. Take real ones from
77
102
  - `narrow` — remove tools or make more of them wait for approval. Never
78
103
  loosens.
79
104
 
105
+ - **`triggers`** — what starts a run, set up on every team's copy when it
106
+ turns the agent on (and kept in step on every publish). Each has a `key`
107
+ (lowercase-hyphenated, unique in the agent: what versions are matched by),
108
+ an optional `prompt` (what to do each time), and `enabled` (default
109
+ `true`; `false` sets it up turned off). Types:
110
+ - `event` — `event` is an integration event (`<slug>.<event>`, as
111
+ `ekanos catalog <product>` lists under `agentEvents`); `filter` holds the
112
+ event's declared filter fields (Zendesk: `organization`, `brand`,
113
+ `group`, `tags`, `reply_as` …).
114
+ - `schedule` — `cron` (5 fields, on a 5-minute boundary) and `timezone`
115
+ (IANA, default `UTC`); give it a `prompt`.
116
+ - `webhook` — each team gets its **own** URL and secret, created or
117
+ rotated by the team in the app. A template never holds a webhook secret.
118
+ - **`links`** — other agents of this Source it may ask (`kind: "talk"`) or
119
+ hand work to (`kind: "delegate"`, `mode: "await"` to wait for the answer,
120
+ default, or `"handoff"` to let go). `to` is the other agent's key. A link
121
+ is made in a team only where that team runs both agents; it appears when
122
+ the team turns the other one on.
123
+ - **`teamOverrides`** — which areas a team may change on its copy:
124
+ `policy`, `triggers`, `links`. **The template wins.** An area that is off
125
+ follows the template exactly and the team cannot change it (it shows
126
+ "Set by your administrator"). An area that is on lets the team keep its
127
+ own differences: its own triggers and on/off for the template's, its own
128
+ links, its own auto/approve answers. Switching an area off again keeps the
129
+ team's differences but stops applying them; switching it back on restores
130
+ them. Omitted: `policy` is off; `triggers` and `links` are off when this
131
+ file declares them and on (the team's, as before) when it does not.
132
+
133
+ ## Editing one area without a file
134
+
135
+ Each of these reads the latest version, changes one thing, and stores the
136
+ result as a new **draft** version (`--publish` also rolls it out, with
137
+ `--yes`). A pulled `agent.json` is left alone; `agents pull` refreshes it.
138
+
139
+ ```
140
+ ekanos agents policy <key> # show
141
+ ekanos agents policy <key> set zendesk_add_comment approve
142
+ ekanos agents policy <key> unset zendesk_add_comment
143
+ ekanos agents policy <key> --reads auto --writes approve
144
+ ekanos agents triggers <key> # list
145
+ ekanos agents triggers <key> add event new-tickets --event zendesk.ticket_created \
146
+ --filter tags=vip,urgent --filter brand=123 --filter reply_as=internal_note
147
+ ekanos agents triggers <key> add schedule weekday-digest --cron "0 9 * * 1-5" \
148
+ --timezone America/Los_Angeles --prompt "Summarize yesterday's escalations."
149
+ ekanos agents triggers <key> add webhook inbound --prompt "Triage the posted ticket."
150
+ ekanos agents triggers <key> remove inbound
151
+ ekanos agents links <key> add billing-agent --kind delegate --mode handoff
152
+ ekanos agents links <key> remove billing-agent
153
+ ekanos agents overrides <key> # show the switches
154
+ ekanos agents overrides <key> enable triggers
155
+ ekanos agents overrides <key> disable policy
156
+ ```
157
+
158
+ `--filter field=value` repeats; a value with commas is a list, `true` or
159
+ `false` a switch, anything else text. `--disabled` adds a trigger turned off.
160
+
80
161
  ## What the host checks on `apply`
81
162
 
82
163
  Every product and tool must be in the Source's catalog, every skill must
@@ -32,7 +32,15 @@ Built with `ekanos agents` by a Source admin.
32
32
  Good for: the same job done by several teams; a central owner who improves
33
33
  it over time; consistent behaviour and approvals.
34
34
 
35
- Piloting: publish, then have one team turn it on first. Teams that never
35
+ **A Source admin can do a team's part from the terminal**:
36
+ `ekanos teams agents enable <team> <key> [--as <member-email>]` turns it on
37
+ for the team (running as that member, the team's owner by default),
38
+ `ekanos teams agents pin|unpin`, `ekanos teams agents policy`, and
39
+ `ekanos teams triggers|links|mcp` set up the rest. `ekanos teams agents list
40
+ <team>` shows where each team stands and what it still needs connected.
41
+
42
+ Piloting: publish, then have one team turn it on first (or turn it on for
43
+ them with `ekanos teams agents enable`). Teams that never
36
44
  turn it on are unaffected. Or keep it as an applied draft until the pilot
37
45
  plan is ready.
38
46
 
@@ -35,12 +35,14 @@ integration: its members, its data and its connections.
35
35
  |---|---|---|---|
36
36
  | **Each team, through the Source's app** | One app, created once for the whole Source under the Source's own name. Each team then signs in through it. | The Source admin creates the app (`references/app-setup.md`, `ekanos apps set`); each team connects | Linear, Slack: products where every team is a separate workspace |
37
37
  | **Each team, with its own app** | Each team creates its own app in the provider and enters its credentials | Each team, or the Source admin on the team's behalf with `ekanos teams` (below) | Zendesk: each bank or business has its own Zendesk |
38
- | **One connection for the whole Source** | Every team's provided agent uses the Source's single connection, limited to what is routed to that team | The Source admin, once | One shared Zendesk for many teams. **Not available yet**: say so, and suggest a connection per team for now |
38
+ | **One connection for the whole Source** | Every team's provided agent uses the Source's single connection, limited to the records routed to that team (for Zendesk, the tickets of the organizations mapped to it) | The Source admin, once, plus a routing table | One shared Zendesk for many teams (§ 5). Only for integrations that declare it (Zendesk from 0.2.0; `agents apply` refuses the others), and only for **provided agents**: a team's own agents, widgets and assistant never use it |
39
39
 
40
40
  The agent records the choice in `agent.json` → `connections`:
41
41
  `{ "zendesk": { "owner": "team", "team": "required" } }` means each team
42
42
  uses its own Zendesk and the agent waits at "needs setup" until it is
43
- connected (`references/agent-json.md`).
43
+ connected (`references/agent-json.md`). `{ "zendesk": { "owner": "source" } }`
44
+ means every team's copy of the agent uses the Source's one Zendesk; teams
45
+ connect nothing for it.
44
46
 
45
47
  ## 3. Walk it, one step per message
46
48
 
@@ -62,7 +64,8 @@ connected (`references/agent-json.md`).
62
64
  provider's console and enter the new one at the terminal.
63
65
  - **Signing in is a person's click.** Connecting (the provider's consent
64
66
  screen) happens in the browser, by someone on the team, from the link in
65
- `teams show`. Tell them who should click it: the account the integration
67
+ `teams show` (or just the link and whether it is connected yet:
68
+ `teams connect <team> <product>`). Tell them who should click it: the account the integration
66
69
  acts as. A dedicated seat such as "Support agent" makes its replies easy
67
70
  to recognise.
68
71
  - **Close each product out**: one line on what now works ("New tickets in
@@ -89,6 +92,59 @@ pilot), the team-side steps can be done from the CLI:
89
92
  5. Someone on the team opens the link from `teams show` and clicks Connect.
90
93
  6. `teams show` again: every step ✓.
91
94
 
95
+ ## 5. One connection for the whole Source
96
+
97
+ Use it when one account at the provider serves many teams: one Zendesk where
98
+ each bank is an organization. The Source admin connects once; events are
99
+ routed to teams by a value inside them (for Zendesk, the ticket's
100
+ **organization**); each team's provided agent then works only inside what is
101
+ routed to that team. Say all three parts before starting, and say plainly
102
+ what it does **not** do: a team's own agents, widgets and assistant never see
103
+ the Source's connection.
104
+
105
+ 1. **Connect, once, as the Source.** For an integration where each customer
106
+ brings its own app (Zendesk), first create that app in the shared account,
107
+ exactly as in the worked example below (OAuth client, Confidential), but
108
+ once, for the Source. Then, **in their own terminal**:
109
+ `npx @ekanos/cli apps connect <product> --source <slug>`. It asks for the
110
+ app's fields it doesn't have yet (Zendesk: subdomain, client ID, client
111
+ secret, webhook signing secret; secrets hidden, never as flags, and it
112
+ refuses to run inside Claude), prints the redirect URL to register and the
113
+ consent link, then waits up to ten minutes until it is connected. Whoever
114
+ clicks the link is the account the integration acts as for every team, so
115
+ suggest a dedicated seat ("Support agent"). `apps list` shows every
116
+ integration the Source can connect this way. Check with
117
+ `npx @ekanos/cli apps show <product> --source <slug>`: connected, by whom,
118
+ when. In the app the same lives in the Source admin area under
119
+ **Shared integrations › Connections**.
120
+ 2. **The Source's webhook.** `npx @ekanos/cli routes webhook <product> --source <slug>`
121
+ prints one URL, **once**, for the whole Source. Paste it into the
122
+ provider at that moment (for Zendesk, the webhook the triggers notify).
123
+ The team webhooks from § 4 are not used for this connection.
124
+ 3. **Map values to teams.** `npx @ekanos/cli routes options <product> --source <slug>`
125
+ lists what can be mapped (Zendesk organizations, with names), then one
126
+ line per team:
127
+ `npx @ekanos/cli routes set <product> <value> <team> --source <slug>`.
128
+ `routes list` shows the table. One value goes to exactly one team.
129
+ 4. **The agent.** In `agent.json`, `connections.<product>` is
130
+ `{ "owner": "source" }`; `agents apply` accepts it only when the
131
+ integration supports a Source connection. Teams turn the agent on as
132
+ usual; they connect nothing for that product.
133
+ 5. **Try it.** A ticket from a mapped organization starts that team's agent
134
+ only. A ticket from an organization nobody mapped starts **nothing**: the
135
+ integration leaves its own fixed note (Zendesk: an internal note saying
136
+ no team has it yet), and it is listed by
137
+ `npx @ekanos/cli routes unrouted <product> --source <slug>`. Map the
138
+ value, then `routes replay <event-id>` to send it on once.
139
+
140
+ What is enforced, so you can say it accurately: the host routes each event
141
+ to exactly one team or to none (never to a default team), and gives a
142
+ team's agent only that team's mapped values (`ctx.routing`); the
143
+ integration's tools keep to them (for Zendesk, reads are limited to the
144
+ team's organizations, and anything that reads or changes one ticket first
145
+ checks its organization and refuses otherwise). The agent's policy,
146
+ approvals and audit apply exactly as on a team connection.
147
+
92
148
  ## Worked example: Zendesk for one team
93
149
 
94
150
  The steps below are what Zendesk's own setup says, in order. Take the URLs
@@ -0,0 +1,81 @@
1
+ # Skills: what an agent knows how to do
2
+
3
+ A skill is a folder — `SKILL.md` plus optional `references/` and `assets/` —
4
+ in the same format Claude Code uses. An agent lists its skills by name and
5
+ description and loads one when the task calls for it.
6
+
7
+ ```
8
+ agents/support-triage/
9
+ agent.json
10
+ AGENT.md
11
+ skills/
12
+ refund-policy/
13
+ SKILL.md # frontmatter: name, description; then the instructions
14
+ references/policy-2026.md
15
+ ```
16
+
17
+ `SKILL.md` frontmatter:
18
+
19
+ ```markdown
20
+ ---
21
+ name: refund-policy
22
+ description: How we decide refunds — use when a customer asks for money back.
23
+ ---
24
+
25
+ # Refund policy
26
+ ...
27
+ ```
28
+
29
+ The slug is `name` when it is lowercase-with-hyphens, else the folder's
30
+ name. The `description` is how the agent decides to load the skill — write it
31
+ as "what it is — when to use it".
32
+
33
+ ## Two levels
34
+
35
+ | Level | Command | Who sees it |
36
+ |---|---|---|
37
+ | **Source** (default) | `ekanos skills push <dir>` | Every team on the Source. An agent template may name it in `skills`. |
38
+ | **Team** | `ekanos skills push <dir> --team <team-slug>` | That one team only. For content another team must not see (one bank's own guide). |
39
+
40
+ Pushing is a Source admin's. A push is **live at once**: there is no draft
41
+ and no publish step, and every agent naming the skill reads the new version
42
+ on its next run. Show the user the folder before pushing it.
43
+
44
+ ## Commands
45
+
46
+ ```bash
47
+ npx @ekanos/cli skills list --source <slug> --json # the Source's + platform skills
48
+ npx @ekanos/cli skills list --team <team> --source <slug> # one team's own
49
+ npx @ekanos/cli skills show <slug> --source <slug> # files, versions
50
+ npx @ekanos/cli skills push agents/<key>/skills/<slug> --source <slug> --json
51
+ npx @ekanos/cli skills pull <slug> --source <slug> [--out <dir>]
52
+ ```
53
+
54
+ `push` prints what changed (files added, changed, removed) and the new
55
+ version; an identical folder is `unchanged` and stores nothing — safe to run
56
+ again.
57
+
58
+ ## With `agents apply`
59
+
60
+ `ekanos agents apply agents/<key>` pushes every `agents/<key>/skills/<slug>/`
61
+ folder at Source level first, then names those slugs in the agent's `skills`
62
+ (you need not repeat them in `agent.json`). `--no-skills` skips that.
63
+ Because pushing needs a Source admin, a `developer` seat applying an agent
64
+ with skill folders gets SOURCE_ADMIN_REQUIRED; pass `--no-skills` and ask a
65
+ Source admin to `skills push` them.
66
+
67
+ A provided agent (template) names Source or platform skills only. A team
68
+ skill is attached by that team to its own agents — or to a provided agent
69
+ whose `teamCustomization.skills` is on.
70
+
71
+ ## Limits today
72
+
73
+ - Prompt skills only. At run time the agent gets the whole folder: loading
74
+ the skill returns `SKILL.md`'s instructions plus the list of every other
75
+ file (`references/`, `assets/`, …), and it reads one on demand
76
+ (`read_skill_file`) when the instructions point to it — so keep `SKILL.md`
77
+ short and name the reference to open, e.g. `references/policy-2026.md`.
78
+ Text files are read in parts of about 12,000 characters; binary files are
79
+ listed but cannot be read as text.
80
+ - A `scripts/` folder is refused: executable skills need the in-app review.
81
+ - Up to 100 files, 1 MB per file, 3 MB per skill.
@@ -1,9 +1,28 @@
1
1
  # What starts the agent: triggers
2
2
 
3
- Triggers belong to each team. They are not part of the agent template: a team
4
- adds them on its copy (Agents → the agent → Triggers) after turning it on.
5
- Your job in the interview is to say which triggers each team will want, and
6
- what it must connect first, so the team-side checklist is complete.
3
+ The template can declare its triggers (`triggers` in `agent.json`, or
4
+ `ekanos agents triggers <key> add …`): every team that turns the agent on gets
5
+ them, and each publish keeps them in step. By default a team cannot change
6
+ them — they show as "Set by your administrator". Turn on
7
+ `teamOverrides.triggers` (`ekanos agents overrides <key> enable triggers`) to
8
+ let teams add their own and turn the template's on or off. A template that
9
+ declares no triggers leaves them to each team, set on its copy (Agents → the
10
+ agent → Triggers) after turning it on.
11
+
12
+ Ask in the interview: should the Source set what starts the agent for every
13
+ team (recommended when every team works the same way), or each team? Either
14
+ way say what each team must connect first, so the checklist is complete.
15
+ A webhook trigger's secret is always per team: the template declares the
16
+ trigger, each team creates or rotates its own secret in the app.
17
+
18
+ A Source admin can add them for the team from the terminal instead:
19
+ `ekanos teams triggers list|add|remove <team> <key> …` — for example
20
+ `ekanos teams triggers add acme-support support-agent event zendesk.ticket_created --filter '{"tags":["billing"]}'`,
21
+ `… schedule --cron "0 9 * * 1-5" --timezone America/Los_Angeles --prompt "…"`,
22
+ `… webhook --prompt "…"` (prints the URL and token once) or `… manual`.
23
+ Slack and Linear triggers are added in the app. When a provided agent's
24
+ template declares triggers and has not turned on team overrides for them, the
25
+ team's triggers follow the template and these commands refuse to change them.
7
26
 
8
27
  ## Kinds a team can add
9
28
 
@@ -45,4 +64,5 @@ internal notes, or approval on public replies, until the team trusts it.
45
64
  it (the agent shows what is missing).
46
65
  3. Do each integration's own setup (team app, webhook) from its guide.
47
66
  4. Confirm access if asked.
48
- 5. Add the triggers above, then run one real example and review it.
67
+ 5. Add the triggers above — unless the template already sets them — then
68
+ run one real example and review it.