@ekanos/cli 0.13.0 → 0.14.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 (173) hide show
  1. package/README.md +25 -8
  2. package/dist/agents-api.d.ts +11 -2
  3. package/dist/agents-api.js +39 -3
  4. package/dist/agents-api.js.map +1 -1
  5. package/dist/apps-api.js +2 -2
  6. package/dist/apps-api.js.map +1 -1
  7. package/dist/auth/ekanos-api.d.ts +16 -2
  8. package/dist/auth/ekanos-api.js +101 -15
  9. package/dist/auth/ekanos-api.js.map +1 -1
  10. package/dist/auth/host-trust.d.ts +46 -0
  11. package/dist/auth/host-trust.js +79 -0
  12. package/dist/auth/host-trust.js.map +1 -0
  13. package/dist/auth/session.d.ts +10 -1
  14. package/dist/auth/session.js +28 -28
  15. package/dist/auth/session.js.map +1 -1
  16. package/dist/commands/agents-edit.d.ts +6 -2
  17. package/dist/commands/agents-edit.js +57 -26
  18. package/dist/commands/agents-edit.js.map +1 -1
  19. package/dist/commands/agents.d.ts +13 -2
  20. package/dist/commands/agents.js +148 -36
  21. package/dist/commands/agents.js.map +1 -1
  22. package/dist/commands/apps.d.ts +2 -0
  23. package/dist/commands/apps.js +16 -12
  24. package/dist/commands/apps.js.map +1 -1
  25. package/dist/commands/catalog.js +7 -6
  26. package/dist/commands/catalog.js.map +1 -1
  27. package/dist/commands/knowledge.d.ts +19 -0
  28. package/dist/commands/knowledge.js +119 -27
  29. package/dist/commands/knowledge.js.map +1 -1
  30. package/dist/commands/login.d.ts +4 -0
  31. package/dist/commands/login.js +30 -2
  32. package/dist/commands/login.js.map +1 -1
  33. package/dist/commands/logout.d.ts +9 -1
  34. package/dist/commands/logout.js +56 -7
  35. package/dist/commands/logout.js.map +1 -1
  36. package/dist/commands/publish.js +3 -3
  37. package/dist/commands/publish.js.map +1 -1
  38. package/dist/commands/reviewers.d.ts +2 -0
  39. package/dist/commands/reviewers.js +7 -3
  40. package/dist/commands/reviewers.js.map +1 -1
  41. package/dist/commands/routes.d.ts +2 -0
  42. package/dist/commands/routes.js +42 -9
  43. package/dist/commands/routes.js.map +1 -1
  44. package/dist/commands/runs.d.ts +13 -2
  45. package/dist/commands/runs.js +96 -15
  46. package/dist/commands/runs.js.map +1 -1
  47. package/dist/commands/scope-notice.d.ts +21 -0
  48. package/dist/commands/scope-notice.js +35 -0
  49. package/dist/commands/scope-notice.js.map +1 -0
  50. package/dist/commands/skills.d.ts +7 -1
  51. package/dist/commands/skills.js +80 -24
  52. package/dist/commands/skills.js.map +1 -1
  53. package/dist/commands/sources.d.ts +1 -1
  54. package/dist/commands/sources.js +126 -12
  55. package/dist/commands/sources.js.map +1 -1
  56. package/dist/commands/status.js +5 -4
  57. package/dist/commands/status.js.map +1 -1
  58. package/dist/commands/team-agent-readiness.d.ts +59 -0
  59. package/dist/commands/team-agent-readiness.js +341 -0
  60. package/dist/commands/team-agent-readiness.js.map +1 -0
  61. package/dist/commands/team-agents-agents.d.ts +24 -3
  62. package/dist/commands/team-agents-agents.js +336 -35
  63. package/dist/commands/team-agents-agents.js.map +1 -1
  64. package/dist/commands/team-agents-mcp.js +32 -3
  65. package/dist/commands/team-agents-mcp.js.map +1 -1
  66. package/dist/commands/team-agents-triggers.js +230 -55
  67. package/dist/commands/team-agents-triggers.js.map +1 -1
  68. package/dist/commands/team-agents.d.ts +3 -1
  69. package/dist/commands/team-agents.js +27 -7
  70. package/dist/commands/team-agents.js.map +1 -1
  71. package/dist/commands/teams-channel-install.d.ts +24 -0
  72. package/dist/commands/teams-channel-install.js +94 -0
  73. package/dist/commands/teams-channel-install.js.map +1 -0
  74. package/dist/commands/teams-connect.d.ts +41 -0
  75. package/dist/commands/teams-connect.js +212 -57
  76. package/dist/commands/teams-connect.js.map +1 -1
  77. package/dist/commands/teams-events.d.ts +12 -0
  78. package/dist/commands/teams-events.js +138 -0
  79. package/dist/commands/teams-events.js.map +1 -0
  80. package/dist/commands/teams-onboard.d.ts +11 -3
  81. package/dist/commands/teams-onboard.js +60 -7
  82. package/dist/commands/teams-onboard.js.map +1 -1
  83. package/dist/commands/teams-overview.d.ts +11 -0
  84. package/dist/commands/teams-overview.js +160 -0
  85. package/dist/commands/teams-overview.js.map +1 -0
  86. package/dist/commands/teams-scope.d.ts +10 -0
  87. package/dist/commands/teams-scope.js +109 -0
  88. package/dist/commands/teams-scope.js.map +1 -0
  89. package/dist/commands/teams.d.ts +4 -2
  90. package/dist/commands/teams.js +113 -14
  91. package/dist/commands/teams.js.map +1 -1
  92. package/dist/commands/upgrade.js +12 -2
  93. package/dist/commands/upgrade.js.map +1 -1
  94. package/dist/commands/use.js +2 -2
  95. package/dist/commands/use.js.map +1 -1
  96. package/dist/commands/whoami.js +1 -1
  97. package/dist/commands/whoami.js.map +1 -1
  98. package/dist/connections-api.js +1 -1
  99. package/dist/connections-api.js.map +1 -1
  100. package/dist/delegate.js +11 -4
  101. package/dist/delegate.js.map +1 -1
  102. package/dist/harness-scaffold.js +12 -0
  103. package/dist/harness-scaffold.js.map +1 -1
  104. package/dist/index.d.ts +6 -0
  105. package/dist/index.js +683 -167
  106. package/dist/index.js.map +1 -1
  107. package/dist/knowledge-api.d.ts +46 -0
  108. package/dist/knowledge-api.js +32 -1
  109. package/dist/knowledge-api.js.map +1 -1
  110. package/dist/open-url.d.ts +16 -0
  111. package/dist/open-url.js +73 -0
  112. package/dist/open-url.js.map +1 -0
  113. package/dist/parse-argv.d.ts +2 -0
  114. package/dist/parse-argv.js.map +1 -1
  115. package/dist/publish-api.d.ts +2 -1
  116. package/dist/publish-api.js +4 -3
  117. package/dist/publish-api.js.map +1 -1
  118. package/dist/pull-write.d.ts +27 -0
  119. package/dist/pull-write.js +60 -0
  120. package/dist/pull-write.js.map +1 -0
  121. package/dist/routes-api.d.ts +3 -0
  122. package/dist/routes-api.js +9 -4
  123. package/dist/routes-api.js.map +1 -1
  124. package/dist/runs-api.d.ts +7 -1
  125. package/dist/runs-api.js +21 -6
  126. package/dist/runs-api.js.map +1 -1
  127. package/dist/safe-fs.d.ts +2 -0
  128. package/dist/safe-fs.js +12 -6
  129. package/dist/safe-fs.js.map +1 -1
  130. package/dist/secret-file.d.ts +17 -0
  131. package/dist/secret-file.js +69 -0
  132. package/dist/secret-file.js.map +1 -0
  133. package/dist/skills-api.d.ts +10 -2
  134. package/dist/skills-api.js +37 -2
  135. package/dist/skills-api.js.map +1 -1
  136. package/dist/source-products-api.d.ts +4 -0
  137. package/dist/source-products-api.js +14 -4
  138. package/dist/source-products-api.js.map +1 -1
  139. package/dist/source-target.js +2 -1
  140. package/dist/source-target.js.map +1 -1
  141. package/dist/sources-api.d.ts +2 -1
  142. package/dist/sources-api.js +3 -2
  143. package/dist/sources-api.js.map +1 -1
  144. package/dist/team-connect-api.d.ts +44 -2
  145. package/dist/team-connect-api.js +19 -7
  146. package/dist/team-connect-api.js.map +1 -1
  147. package/dist/teams-api.d.ts +41 -1
  148. package/dist/teams-api.js +97 -19
  149. package/dist/teams-api.js.map +1 -1
  150. package/dist/toolchain-api.d.ts +9 -0
  151. package/dist/toolchain-api.js +17 -2
  152. package/dist/toolchain-api.js.map +1 -1
  153. package/dist/toolchain-resolve.d.ts +3 -0
  154. package/dist/toolchain-resolve.js +15 -1
  155. package/dist/toolchain-resolve.js.map +1 -1
  156. package/dist/toolchain.d.ts +6 -0
  157. package/dist/toolchain.js +19 -0
  158. package/dist/toolchain.js.map +1 -1
  159. package/dist/update-notice.js +2 -1
  160. package/dist/update-notice.js.map +1 -1
  161. package/package.json +2 -2
  162. package/templates/AGENTS.md.tmpl +6 -1
  163. package/templates/claude-skill.md.tmpl +5 -0
  164. package/templates/package.json.tmpl +4 -4
  165. package/templates/skills/build-agent/SKILL.md +103 -17
  166. package/templates/skills/build-agent/references/agent-json.md +4 -2
  167. package/templates/skills/build-agent/references/rollout.md +27 -4
  168. package/templates/skills/build-agent/references/set-up-an-integration.md +55 -7
  169. package/templates/skills/build-agent/references/skills.md +20 -1
  170. package/templates/skills/build-agent/references/triggers.md +46 -11
  171. package/templates/skills/build-integration/references/widget-design.md +3 -3
  172. package/templates/skills/ekanos-platform/SKILL.md +43 -16
  173. package/templates/skills/polish-widgets/references/patterns.md +2 -2
@@ -18,13 +18,33 @@ Run the CLI as `npx @ekanos/cli … --json` and read the envelope
18
18
  every `hint`. Look things up in the `ekanos-sdk-docs` MCP server
19
19
  (https://sdk.ekanos.dev) rather than guessing.
20
20
 
21
+ ## The goal: an agent that can be reached and answers
22
+
23
+ The user wants an agent that **responds and does things** where their people
24
+ work — someone @mentions it in Linear (or assigns it an issue, or writes in
25
+ Slack) and it picks the work up, acts with its tools and answers in that
26
+ thread. "Published", "turned on" and "connected" are steps toward that, not
27
+ the finish. Whenever the agent has a channel trigger (`linear.mentioned`,
28
+ `linear.assigned`, any Linear event, a Slack trigger), the job is not done
29
+ until a real mention has started a run and the reply has landed.
30
+
31
+ A channel trigger fires only once that channel is **installed for the team**,
32
+ and for Linear that is a second identity beside the personal connection: the
33
+ team's own Linear app installed as a workspace member (the `agent`
34
+ connection). The personal connection lets the agent's tools act; only the
35
+ installed Linear agent makes Linear send the mention. Nothing stops a team
36
+ from turning the agent on with the trigger saved and the agent never
37
+ installed — so check it, every time (§ 4, "Make it reachable").
38
+
21
39
  ## Hard rules
22
40
 
23
41
  - Never ask for, accept or write a secret (API key, client secret, webhook
24
- signing secret). Teams enter those in the Ekanos app.
25
- - Never `publish` or `rollback` without the user's explicit yes to that
26
- version, after they have seen it. `--yes` records that consent; it is never
27
- a way past a question.
42
+ signing secret). The user types it at their own terminal — `apps set`,
43
+ `apps connect`, `teams app set` and `teams connect` ask with hidden input
44
+ and refuse an agent run — or a team enters it in the Ekanos app.
45
+ - Never `publish`, `rollback` or `archive` without the user's explicit yes to
46
+ that version or agent, after they have seen it. `--yes` records that
47
+ consent; it is never a way past a question.
28
48
  - Never `--overwrite` a version conflict (exit 7) you have not shown the user:
29
49
  someone else changed the agent; pull it and reconcile.
30
50
  - Use product and tool names exactly as the catalog lists them.
@@ -53,7 +73,8 @@ every `hint`. Look things up in the `ekanos-sdk-docs` MCP server
53
73
  agent's docs, policies or FAQs should live, offer **Knowledge** first:
54
74
  Ekanos's own knowledge base, nothing to sign up for. One collection per
55
75
  team plus the Source's General one; load a folder of markdown with
56
- `ekanos knowledge push <dir> [--team <team>]`, check with
76
+ `ekanos knowledge push <dir> [--team <team>]` (add `--prune` on the
77
+ user's yes to delete the ones whose files they removed), check with
57
78
  `ekanos knowledge search "<words>" --team <team>`, and grant the agent
58
79
  `search_knowledge` + `read_knowledge_article` (`references/agent-json.md`
59
80
  → `tools`). Keep skills for how-to-work instructions; Knowledge for the
@@ -122,7 +143,10 @@ in parentheses are the recommendation when the user has no preference.
122
143
  event a product declares (Linear also has `linear.issue_labeled`,
123
144
  `linear.issue_created` and `linear.assigned`; Zendesk also has
124
145
  `zendesk.comment_added`) — map an old trigger onto the matching event
125
- rather than onto an @mention. Say what each team needs connected first.
146
+ rather than onto an @mention. Say what each team needs connected first —
147
+ and for a channel trigger, that each team also installs that channel's
148
+ agent (Linear: `teams connect <team> linear --connection agent`), or the
149
+ trigger never fires.
126
150
  8. **Who it works with** — other agents of this Source it may ask or hand
127
151
  work to (`links`). A link only exists in a team that runs both agents.
128
152
  9. **What teams may change** — `teamOverrides` per area (approvals,
@@ -150,21 +174,80 @@ in parentheses are the recommendation when the user has no preference.
150
174
  `skills` the output reports as created or changed.
151
175
  3. `npx @ekanos/cli agents show <key> --source <slug>` — review the stored draft
152
176
  with the user.
153
- Then test it on one team that has turned the agent on, without publishing:
177
+ Then test it on **one** team, without publishing. Put that team on the
178
+ draft first — this works before anything is published, and lets the test
179
+ use tools the draft adds:
180
+ `npx @ekanos/cli teams agents enable <team> <key> --draft --json` (agent
181
+ not on that team yet) or `teams agents pin <team> <key> --draft --json`
182
+ (already on). Then
154
183
  `npx @ekanos/cli agents test <key> --team <team> --prompt "…" --follow --json`
155
- (or `--input example.json` for a real ticket or event). It runs the latest
156
- version on that team as a test run — same tools, approvals and audit; the
157
- team's current agent still bounds what it may do, so a draft can only do
158
- less. A write waits for an approval like any run (see "Running, watching
159
- and deciding" below).
184
+ (or `--input example.json` for a real ticket or event). Only that team runs
185
+ the draft, only when started by hand — its triggers don't start it — and
186
+ every write waits for an approval (see "Running, watching and deciding"
187
+ below). After the next `agents apply`, run `pin --draft` again to test the
188
+ new draft; publishing puts the team back to following.
160
189
  4. Ask: publish this version to every team now? Only on yes:
161
190
  `npx @ekanos/cli agents publish <key> --source <slug> --to <n> --yes`.
191
+ When the user is the person the agent runs as on their teams, ask once
192
+ whether to add `--confirm-access` (it confirms, as them, that the agent
193
+ may use their connections there, and moves those teams at once; never
194
+ add it without their yes). A version that reaches further than a team
195
+ confirmed does not break that team: it is **held** on the version it
196
+ runs until the person it runs as confirms. The output lists each held
197
+ team, what the new version adds, who confirms and the `teams agents
198
+ confirm` command (which moves it) — relay it; never send them to the app
199
+ for it.
162
200
  5. If anything waits for approval, name its reviewers (**Reviewers**
163
201
  below) before teams turn it on — a draft nobody may decide just waits.
164
202
  6. Hand over the team-side checklist (`references/triggers.md` has the
165
203
  per-integration parts): find it under Agents → "Provided for your team",
166
- Turn on, connect what it needs, confirm access, add triggers. Suggest one
167
- team pilots it first, and plan a first test run with them.
204
+ Turn on, connect what it needs, **install the channel's agent for a
205
+ channel trigger**, confirm access (`teams agents confirm <team> <key>`,
206
+ by the person it runs as, or `teams agents enable … --confirm-access`
207
+ when that is the user), add triggers. Suggest one team pilots
208
+ it first, and do § 4 with them.
209
+
210
+ ## 4. Make it reachable, and prove it end to end
211
+
212
+ For each team that turns on an agent with a channel trigger, start with
213
+ `npx @ekanos/cli teams agents show <team> <key> --source <slug>`: it says
214
+ whether the agent is live on that team and, if not, the one next step
215
+ (`npx @ekanos/cli teams show <team> --source <slug>` is the whole team on one
216
+ screen). For the detail behind it:
217
+
218
+ 1. `npx @ekanos/cli teams agents list <team> --json` — each agent's
219
+ `channels` says what its triggers need installed (`ready`, `problem`).
220
+ A `ready: false` entry is a trigger that can never fire; its `problem`
221
+ reads "Linear agent not installed for this team".
222
+ 2. `npx @ekanos/cli teams show <team> linear --json` — `connections` has one
223
+ entry per connection: `default` (the personal connection: `connected`)
224
+ and `agent` (`credentialsSaved`, `connected` = installed, `neededBy`),
225
+ and the `agent-events` webhook in `teamApps[].webhooks` must have an
226
+ `endpoint`. Read the state back to the user in those words.
227
+ 3. Not installed: the user runs, **in their own terminal** (it asks for the
228
+ Linear app's secrets, which you never handle):
229
+ `npx @ekanos/cli teams connect <team> linear --connection agent --source <slug>`.
230
+ It asks for the app's client ID, secret and webhook signing secret if
231
+ missing, opens the install (a Linear workspace admin approves it) and
232
+ waits. No webhook URL yet: `npx @ekanos/cli teams webhook <team> linear
233
+ agent-events --source <slug>` (shown once, and saved to a file only the
234
+ user can read — the output names it; the user copies it into the Linear
235
+ app. Never open or print that file yourself).
236
+ `references/set-up-an-integration.md` § 4 has the app walk-through. Then
237
+ run step 2 again until `agent` reads `connected: true` with a webhook.
238
+ 4. The real check, never skipped: ask the user to @mention the agent on a
239
+ Linear issue (or assign it one). Then
240
+ `npx @ekanos/cli runs list --team <team> --json` shows a run whose
241
+ `trigger` is the event (`integration_event`), started in the last minute;
242
+ `npx @ekanos/cli runs show <run-id> --team <team> --json` shows its work,
243
+ and the user confirms the reply landed in the Linear thread. No run:
244
+ go back to step 1 — the trigger, its filter (`teamKeys`), the webhook
245
+ events ticked in the Linear app (**Agent session events**), the latest
246
+ webhook URL.
247
+
248
+ `agents test` and `runs start` run the agent by hand: they pass without the
249
+ channel, so they never prove it. When the agent's real trigger could never
250
+ fire they print a `Warning:` (and `warnings` in `--json`) — act on it.
168
251
 
169
252
  ## Reviewers
170
253
 
@@ -181,7 +264,7 @@ notified of every draft in their reach.
181
264
  - `npx @ekanos/cli reviewers add <email> --reach team --team <team-slug> --source <slug>`
182
265
  — decides one team's drafts, from the same review queue (they need not be
183
266
  a member of that team).
184
- - `npx @ekanos/cli reviewers remove <email> [--team <team-slug>] --source <slug>`
267
+ - `npx @ekanos/cli reviewers remove <email> [--team <team-slug>] --source <slug> --yes`
185
268
  — every reach, or just that team's.
186
269
 
187
270
  The first decision settles a draft for everyone. Recommend one or two
@@ -192,7 +275,8 @@ reviewers where a team wants its own people deciding. A refusal with
192
275
  ## Changing it later
193
276
 
194
277
  `npx @ekanos/cli agents pull <key> --source <slug>` writes the latest version to
195
- `agents/<key>/`; edit, `apply` (a new draft), `show`, then `publish` on the
278
+ `agents/<key>/` (it refuses to overwrite a local file that differs; `--force`
279
+ replaces it); edit, `apply` (a new draft), `show`, then `publish` on the
196
280
  user's yes. For one small change, edit the stored draft directly — `agents
197
281
  policy <key> set <tool> approve`, `agents triggers <key> add|remove …`,
198
282
  `agents links <key> add|remove …`, `agents overrides <key> enable|disable
@@ -219,7 +303,9 @@ names them). Add `--json` for a stable record a script can assert on.
219
303
  - `npx @ekanos/cli approvals list --team <team>` — what is waiting.
220
304
  - `npx @ekanos/cli approvals approve <id> --team <team> [--reason "…"]` /
221
305
  `approvals reject <id> --team <team> --reason "…"` — decided as you, with
222
- the authority a team's agent manager has in the app.
306
+ the authority a team's agent manager has in the app. A team's own agent
307
+ (not provided) is the team's: you decide its approvals only as a member of
308
+ that team who manages its agents (`NOT_A_TEAM_APPROVER` otherwise).
223
309
  - `npx @ekanos/cli approvals edit <id> --team <team> --body ./reply.md` — Edit &
224
310
  send a reply draft: approves it with your text instead. Only reply drafts
225
311
  take an edit.
@@ -126,7 +126,8 @@ The tool names above are illustrations. Take real ones from
126
126
  - `schedule` — `cron` (5 fields, on a 5-minute boundary) and `timezone`
127
127
  (IANA, default `UTC`); give it a `prompt`.
128
128
  - `webhook` — each team gets its **own** URL and secret, created or
129
- rotated by the team in the app. A template never holds a webhook secret.
129
+ rotated by the team in the app or by a Source admin with
130
+ `ekanos teams triggers rotate`. A template never holds a webhook secret.
130
131
  - **`links`** — other agents of this Source it may ask (`kind: "talk"`) or
131
132
  hand work to (`kind: "delegate"`, `mode: "await"` to wait for the answer,
132
133
  default, or `"handoff"` to let go). `to` is the other agent's key. A link
@@ -146,7 +147,8 @@ The tool names above are illustrations. Take real ones from
146
147
 
147
148
  Each of these reads the latest version, changes one thing, and stores the
148
149
  result as a new **draft** version (`--publish` also rolls it out, with
149
- `--yes`). A pulled `agent.json` is left alone; `agents pull` refreshes it.
150
+ `--yes`). A pulled `agent.json` is left alone; `agents pull --force` refreshes
151
+ it (without `--force`, a pull refuses to overwrite a file that differs).
150
152
 
151
153
  ```
152
154
  ekanos agents policy <key> # show
@@ -22,19 +22,42 @@ Built with `ekanos agents` by a Source admin.
22
22
  when a newer one is published.
23
23
  - **Rollback.** `ekanos agents rollback <key> --to <n> --yes` publishes an
24
24
  earlier version to every team that follows it.
25
+ - **Retiring it.** `ekanos agents archive <key> --yes` stops every team from
26
+ turning it on; it cannot be applied over or published until
27
+ `ekanos agents unarchive <key>`. It is refused while any team has it on,
28
+ and the refusal lists each team with the `teams agents disable` command
29
+ that turns it off there. `agents list` hides archived agents (`--all`
30
+ shows them). Archive only on the user's explicit yes.
25
31
  - **What stays the team's:** whether it is on, its triggers, its own
26
32
  connections, its run history, and whatever `teamCustomization` lets it add.
33
+ - **Confirming access.** The agent uses the connections of the person it
34
+ runs as, and in runs no one watches only once that person confirms it may:
35
+ `ekanos teams agents confirm <team> <key>`, signed in as themselves (or
36
+ `teams agents enable <team> <key> --confirm-access` to turn it on as
37
+ yourself and confirm at once). Nobody confirms for anyone else.
27
38
  - **When a new version needs more access** than a team confirmed (a new
28
- product, a tool that now runs without approval), the team's owner is asked
29
- to confirm again; until then the agent keeps only what needs no new
30
- confirmation.
39
+ product or tool, `custom` → `read_only`/`all`, a tool that now runs without
40
+ approval), that team is **held**: it keeps running the version it is on,
41
+ confirmed and working, and the new one waits until the person it runs as
42
+ confirms it — `ekanos teams agents confirm <team> <key>`, which prints the
43
+ version it confirms and moves the team to it at once (or **Confirm and
44
+ update** on the agent's page); a version published after that is refused,
45
+ not confirmed unseen. Nobody
46
+ else can move it. Skills, instructions, model, triggers and links never
47
+ hold a team. `agents publish` lists every held team, what the version adds,
48
+ who confirms and the command; `agents publish --confirm-access` confirms,
49
+ and moves, every team where the agent runs as the publisher. `teams agents
50
+ list|show` say "held on vN, vM waiting for confirmation" — the agent is
51
+ still live. A held team that gets another publish waits for the newest; a
52
+ team that never confirmed simply moves; a pinned team stays on its pin.
31
53
 
32
54
  Good for: the same job done by several teams; a central owner who improves
33
55
  it over time; consistent behaviour and approvals.
34
56
 
35
57
  **A Source admin can do a team's part from the terminal**:
36
58
  `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),
59
+ for the team (running as that member, the team's owner by default; with
60
+ `--confirm-access`, as you, confirmed in the same step),
38
61
  `ekanos teams agents pin|unpin`, `ekanos teams agents policy`, and
39
62
  `ekanos teams triggers|links|mcp` set up the rest. `ekanos teams agents list
40
63
  <team>` shows where each team stands and what it still needs connected.
@@ -18,7 +18,10 @@ guess.
18
18
  3. For a team: `npx @ekanos/cli teams show <team> <product> --source <slug> --json`
19
19
  shows what that team has already done (app fields entered, webhook URL
20
20
  minted, connected, who connected and when) and the link to the team's page
21
- in the app.
21
+ in the app. If it says the product is hidden from the team by its product
22
+ scope, the team cannot see it in the app however connected it is: show
23
+ the user the fix it prints (`ekanos sources scopes add <scope> <product>`,
24
+ or `ekanos teams scope set <team> <scope>`) and run it on their yes.
22
25
 
23
26
  Then tell the user, in two or three lines, what is done, what is left, and
24
27
  who does each remaining step. If a step needs Ekanos (the product is not
@@ -102,6 +105,34 @@ pilot), the team-side steps can be done from the CLI:
102
105
  5. Someone on the team opens the link from `teams show` and clicks Connect.
103
106
  6. `teams show` again: every step ✓.
104
107
 
108
+ ### A channel's own install: the Linear agent
109
+
110
+ Some integrations have a second connection beside the main one, and an
111
+ agent's channel trigger fires only once it is installed. Linear's is
112
+ `agent`: the team's own Linear app, installed in the team's Linear workspace
113
+ as a member people can @mention and assign. The personal connection
114
+ (`teams connect <team> linear`) is a different identity and does not make
115
+ mentions arrive. When the agent has any Linear trigger:
116
+
117
+ 1. `teams show <team> linear --json` → `connections`: the `agent` entry's
118
+ `credentialsSaved`, `connected` (installed) and `neededBy` (the agents
119
+ waiting on it), and in `teamApps` the `agent-events` webhook's `endpoint`.
120
+ 2. The Linear app itself (Linear › Settings › API › Applications › New): the
121
+ steps are in `teams show` under "Team app: Linear agent (agent)" —
122
+ redirect URIs, webhooks on with **Agent session events** and **Issues**.
123
+ 3. Its webhook URL: `teams webhook <team> linear agent-events` (once; paste
124
+ it into the Linear app's webhook URL).
125
+ 4. **In their own terminal:**
126
+ `npx @ekanos/cli teams connect <team> linear --connection agent --source <slug>`
127
+ — asks for the client ID, secret and webhook signing secret if any is
128
+ missing, opens the install for a Linear workspace admin to approve, and
129
+ waits until it is installed. (`teams connect <team> linear` with no
130
+ `--connection` offers this itself once the personal connection is made,
131
+ when the team has agents with Linear triggers.)
132
+ 5. `teams show` again: `✓ Linear agent (agent): app credentials saved ·
133
+ installed … · webhook URL made`. Then the end-to-end check in the
134
+ build-agent skill, § 4: a real @mention starts a run and the reply lands.
135
+
105
136
  ## 5. One connection for the whole Source
106
137
 
107
138
  Use it when one account at the provider serves many teams: one Zendesk where
@@ -130,6 +161,9 @@ the Source's connection.
130
161
  2. **The Source's webhook.** `npx @ekanos/cli routes webhook <product> --source <slug>`
131
162
  prints one URL, **once**, for the whole Source. Paste it into the
132
163
  provider at that moment (for Zendesk, the webhook the triggers notify).
164
+ Once a URL is live the command refuses to mint another: a new one
165
+ revokes it for every routed team. Add `--yes` only when the user is
166
+ ready to paste the new URL into the provider.
133
167
  The team webhooks from § 4 are not used for this connection.
134
168
  3. **Map values to teams.** `npx @ekanos/cli routes options <product> --source <slug>`
135
169
  lists what can be mapped (Zendesk organizations, with names), then one
@@ -171,16 +205,23 @@ from `teams show zendesk`.
171
205
  their terminal: subdomain, client ID, client secret, webhook signing
172
206
  secret. Any of them can be entered or changed later on its own
173
207
  (`--field <name>`); `teams show` says which are saved.
174
- 4. **Connect.** Someone on the team opens the link and connects, as the
175
- Zendesk agent the integration should reply as.
208
+ 4. **Connect.** `npx @ekanos/cli teams connect <team> zendesk --source <slug>`
209
+ opens the sign-in and waits; whoever approves it should be the Zendesk
210
+ agent the integration replies as (`--as <member-email>` to send the link
211
+ to that member instead). A team member can also connect from the team's
212
+ page in the app.
176
213
  5. **Zendesk triggers.** Objects and rules › Triggers: one for *Ticket is
177
214
  Created* and one for a customer's public reply, each notifying the webhook
178
215
  with the body from the steps. `"reply_as": "internal"` makes the agent's
179
216
  answer an internal note a person reviews before the customer sees it.
180
217
  Recommend that until the team trusts the agent; `"public"` lets it answer
181
218
  the customer directly.
182
- 6. **The agent's trigger.** In the app, on the agent: *A ticket is created*
183
- (and *A customer replies*), with any filters.
219
+ 6. **The agent's trigger.** In the template, for every team:
220
+ `npx @ekanos/cli agents triggers <key> add event new-tickets --event zendesk.ticket_created --source <slug>`
221
+ (and `zendesk.comment_added` for a customer's reply), with any
222
+ `--filter field=a,b`. For one team only, where the template lets teams
223
+ change triggers:
224
+ `npx @ekanos/cli teams triggers add <team> <key> event zendesk.ticket_created --source <slug>`.
184
225
  7. **Try it.** Open a test ticket as a customer and watch: the agent reads
185
226
  the ticket, looks things up, and answers on it. If it wants to change the
186
227
  ticket (status, priority, assignee), it leaves an internal note saying
@@ -194,7 +235,14 @@ from `teams show zendesk`.
194
235
  - **Tickets don't start the agent:** `teams show` should list a live webhook
195
236
  that has been used recently. If it has never been used, the provider is not
196
237
  calling it: check the Zendesk trigger's conditions and that it notifies the
197
- right webhook. If it has been used but nothing ran, check that the agent has
198
- a trigger for that event and that the team connected the product.
238
+ right webhook. If it has been used but nothing ran, run
239
+ `teams events <team> zendesk --since 24h`: each event says whether it
240
+ started a run, and if not, why (no enabled trigger subscribes to it, none
241
+ matched its filter, or it failed with the error shown).
242
+ - **Mentions in Linear do nothing:** `teams agents list <team>` — a
243
+ `channels` entry with `ready: false` names what is missing ("Linear agent
244
+ not installed for this team", or no webhook URL) and the command that
245
+ fixes it. Installed and still silent: the Linear app's webhook must send
246
+ **Agent session events** to the latest URL from `teams webhook`.
199
247
  - **A command says it needs a terminal:** it was run inside Claude. Ask them
200
248
  to run it in a terminal tab themselves.
@@ -37,6 +37,19 @@ as "what it is — when to use it".
37
37
  | **Source** (default) | `ekanos skills push <dir>` | Every team on the Source. An agent template may name it in `skills`. |
38
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
39
 
40
+ A template can't name a team skill, so a provided agent reads one only once
41
+ it is **attached** on that team, and only when the template allows team
42
+ skills (`"teamCustomization": { "skills": true }` in `agent.json`, applied
43
+ and published):
44
+
45
+ ```bash
46
+ npx @ekanos/cli teams agents skills <team> <key> --source <slug> # what it reads, and whether the team may add
47
+ npx @ekanos/cli teams agents skills <team> <key> add <skill-slug> --source <slug> # attach (team, Source or platform skill)
48
+ npx @ekanos/cli teams agents skills <team> <key> remove <skill-slug> --source <slug>
49
+ ```
50
+
51
+ The template's own skills stay; `remove` refuses them.
52
+
40
53
  Pushing is a Source admin's. A push is **live at once**: there is no draft
41
54
  and no publish step, and every agent naming the skill reads the new version
42
55
  on its next run. Show the user the folder before pushing it.
@@ -48,13 +61,19 @@ npx @ekanos/cli skills list --source <slug> --json # the Source's +
48
61
  npx @ekanos/cli skills list --team <team> --source <slug> # one team's own
49
62
  npx @ekanos/cli skills show <slug> --source <slug> # files, versions
50
63
  npx @ekanos/cli skills push agents/<key>/skills/<slug> --source <slug> --json
51
- npx @ekanos/cli skills pull <slug> --source <slug> [--out <dir>]
64
+ npx @ekanos/cli skills pull <slug> --source <slug> [--out <dir>] [--force] # --force: overwrite local edits
52
65
  ```
53
66
 
54
67
  `push` prints what changed (files added, changed, removed) and the new
55
68
  version; an identical folder is `unchanged` and stores nothing — safe to run
56
69
  again.
57
70
 
71
+ `npx @ekanos/cli skills archive <slug> [--team <team>] --source <slug> --yes`
72
+ retires a skill (only on the user's explicit yes): no agent can name it and a
73
+ push to it is refused until `skills unarchive <slug>`. It is refused while an
74
+ agent names it or a team agent has it attached; the refusal lists each use
75
+ and the command that stops it. Platform skills cannot be archived.
76
+
58
77
  ## With `agents apply`
59
78
 
60
79
  `ekanos agents apply agents/<key>` pushes every `agents/<key>/skills/<slug>/`
@@ -13,7 +13,11 @@ Ask in the interview: should the Source set what starts the agent for every
13
13
  team (recommended when every team works the same way), or each team? Either
14
14
  way say what each team must connect first, so the checklist is complete.
15
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.
16
+ trigger, each team creates or rotates its own secret in the app, or a
17
+ Source admin does with `ekanos teams triggers rotate <team> <key> <trigger-key>`
18
+ (shown once, saved to a file only the user can read and named in the
19
+ output — the user copies it to the sender; never open or print that file
20
+ yourself; replacing a live one needs `--yes`).
17
21
 
18
22
  A Source admin can add them for the team from the terminal instead:
19
23
  `ekanos teams triggers list|add|remove <team> <key> …` — for example
@@ -22,9 +26,15 @@ A Source admin can add them for the team from the terminal instead:
22
26
  `… webhook --prompt "…"` (prints the URL and token once) or `… manual`.
23
27
  Any event in a connected integration's `agentEvents` is added this way,
24
28
  including every Linear integration event (`event linear.issue_labeled
25
- --filter '{"labels":["feedback"]}'`). Only two trigger *types* are app-only:
26
- a **Slack** trigger, and a **Linear (Agents app)** trigger — Ekanos's own
27
- Linear app, which answers @mentions and assignments only. That app is not
29
+ --filter '{"labels":["feedback"]}'`). A **Slack** trigger and a **Linear
30
+ (Agents app)** trigger — Ekanos's own Linear app, which answers @mentions
31
+ and assignments — answer through an install the team makes first:
32
+ `ekanos teams connect <team> slack` or `ekanos teams connect <team>
33
+ linear-app` (a one-time link for a team member, opened and waited on like
34
+ any `teams connect`). Then `ekanos teams triggers add <team> <key> slack
35
+ --channel '#support' [--dms] --yes` (the bot must be in each channel; `--yes`
36
+ confirms that anyone there can ask the agent to act) or `… linear [--label
37
+ <name>]… [--no-mention]`. That app is not
28
38
  the Linear integration, and its limits are not the integration's: an agent
29
39
  that should start when a label is applied uses `linear.issue_labeled`, not an
30
40
  @mention. When a provided agent's
@@ -58,11 +68,28 @@ finishes that event's own setup on the provider's side. That is a setup
58
68
  step, not a missing event — say which step, as below.
59
69
 
60
70
  **Linear** — the agent becomes a teammate in Linear. Each team needs two
61
- things in the app: each person's own Linear connection (for the tools), and
62
- the team's own Linear app for the agent (client id, secret and webhook
63
- signing secret, entered in Ekanos).
71
+ identities, and they are not the same thing:
72
+
73
+ - **The personal connection** (`default`): someone's own Linear sign-in, for
74
+ the agent's tools. `teams connect <team> linear`.
75
+ - **The Linear agent** (`agent`): the team's own Linear app, installed in its
76
+ workspace as a member people can @mention and assign. Linear sends every
77
+ agent event below only to an installed app, so **without it no Linear
78
+ trigger ever fires** — the trigger is saved, on, and silent.
79
+ `teams connect <team> linear --connection agent` (asks for the app's client
80
+ id, secret and webhook signing secret, opens the install, waits), plus the
81
+ webhook URL: `teams webhook <team> linear agent-events`.
82
+
83
+ Check both with `teams show <team> linear`: under **Connections**, `default`
84
+ connected, and `agent` with app credentials saved, installed and its webhook
85
+ URL made. `teams agents list <team>` lists a Linear-triggered agent whose
86
+ agent is not installed as missing ("Linear agent not installed for this
87
+ team"), and the agent's Setup tab in the app says the same.
64
88
  Guide: https://sdk.ekanos.dev/guides/linear-agent
65
89
 
90
+ Every event needs the Linear agent installed; the last column is what the
91
+ installed app's webhook must also send.
92
+
66
93
  | Event | Starts when | Filter keys | Needs on the team's Linear app |
67
94
  |---|---|---|---|
68
95
  | `linear.mentioned` | someone @mentions the agent, or writes to it again in that conversation | `teamKeys` | webhook with **Agent session events** ticked |
@@ -91,7 +118,15 @@ brands, groups and organizations match by name or id. Where the answer goes
91
118
  1. Agents → "Provided for your team" → Turn on.
92
119
  2. Connect every `required` product and sign in to any MCP server that needs
93
120
  it (the agent shows what is missing).
94
- 3. Do each integration's own setup (team app, webhook) from its guide.
95
- 4. Confirm access if asked.
96
- 5. Add the triggers above — unless the template already sets them — then
97
- run one real example and review it.
121
+ 3. Install the channel each trigger listens on: for any Linear trigger the
122
+ Linear agent (`teams connect <team> linear --connection agent`, and its
123
+ webhook URL), for a Slack trigger the team's Slack. `teams agents list
124
+ <team>` shows each agent's `channels`; none may be `ready: false`.
125
+ 4. Do each integration's own setup (team app, webhook) from its guide.
126
+ 5. Confirm access: the person it runs as runs `npx @ekanos/cli teams agents
127
+ confirm <team> <key> --source <slug>` as themselves (or turned it on with
128
+ `--confirm-access`). `teams agents list <team>` shows anyone still to.
129
+ 6. Add the triggers above — unless the template already sets them.
130
+ 7. Prove it end to end: a real @mention (or the real event) → a run in
131
+ `runs list --team <team>` → the agent's reply where it was asked. A test
132
+ run started by hand does not count; it passes without the channel.
@@ -77,9 +77,9 @@ import {
77
77
  </Stat>;
78
78
  ```
79
79
 
80
- - `StatLabel` is uppercase `text-xs` — the one place `text-xs` is a primary
81
- label. `StatValue` is the heading face at `text-2xl`, `tracking-tight`,
82
- `tabular-nums`. Do not override those sizes.
80
+ - `StatLabel` is the uppercase `text-eyebrow` overline. `StatValue` is
81
+ `figure`: the heading face at the Headline tier, tabular. Do not override
82
+ those sizes.
83
83
  - `StatChange`'s `tone` is the READING, not the direction: expenses falling is
84
84
  `positive`. It pairs an arrow glyph with the color, so the tone never rides
85
85
  on hue alone.
@@ -48,6 +48,7 @@ command takes `--source <slug>` (else the Source `ekanos use` set) and
48
48
  ```sh
49
49
  npx @ekanos/cli teams create "Bank A" --slug bank-a # you are its owner
50
50
  npx @ekanos/cli teams create "Bank A" --owner ana@bank-a.com # ana is invited as owner
51
+ npx @ekanos/cli teams rename bank-a "Bank A Support" # the slug follows the name
51
52
  npx @ekanos/cli teams roles list bank-a # roles + permissions (e.g. agents.review)
52
53
  npx @ekanos/cli teams members invite bank-a raj@bank-a.com --role admin # default role: member
53
54
  npx @ekanos/cli teams members list bank-a # members and pending invitations
@@ -92,7 +93,12 @@ Everything in the catalog (`npx @ekanos/cli catalog --source <slug> --json`) is
92
93
  `linear.issue_labeled` and `linear.issue_created`; Zendesk declares
93
94
  `zendesk.ticket_created` and `zendesk.comment_added`. The catalog's
94
95
  `agentEvents` is the authority: read it before concluding a product lacks
95
- an event, never infer the set from an example.
96
+ an event, never infer the set from an example. An event can also need a
97
+ **channel install** before it ever fires: every Linear event arrives only
98
+ through the team's Linear agent (`teams connect <team> linear --connection
99
+ agent`), a second identity beside the personal connection. `teams agents
100
+ list` names any agent whose trigger waits on one (`channels`, `ready:
101
+ false`).
96
102
  - **Experience** — an Ekanos-native capability (Agents, Workflows, Home…).
97
103
  Never "connected"; it is simply on or off for the Source.
98
104
 
@@ -161,9 +167,11 @@ every team can use them, with `--team <slug>` only that team can.
161
167
 
162
168
  **Knowledge** is Ekanos's own knowledge base (no outside account): markdown
163
169
  articles, one collection per team plus the Source's **General** collection
164
- every team reads. A Source admin loads folders of `.md` with
165
- `ekanos knowledge push <dir> [--team <slug>]`; team members edit theirs in
166
- the app (Agents → Knowledge). Agents granted `search_knowledge` /
170
+ that every team's agents granted `search_knowledge` also read. A Source admin loads folders of `.md` with
171
+ `ekanos knowledge push <dir> [--team <slug>]` (`--prune` also deletes the
172
+ articles an earlier push of that folder made whose files are gone, never
173
+ ones written or edited in the app); team members edit theirs in the app
174
+ (Agents → Knowledge). Agents granted `search_knowledge` /
167
175
  `read_knowledge_article` search their own team's collection and General.
168
176
  Skills say *how* to work; Knowledge holds the facts an agent looks up.
169
177
 
@@ -176,21 +184,36 @@ always `ekanos teams <area> <verb> <team> …`:
176
184
  - `ekanos teams agents list <team>` — provided agents, on or off, the version
177
185
  each runs (pinned or following), triggers, links, the team's MCP servers,
178
186
  and what each still needs connected.
179
- - `ekanos teams agents enable <team> <key> [--as <member-email>]` /
180
- `disable <team> <key>` — the app's "Turn on" / "Turn off". The agent runs
181
- as a team member who manages agents (the team's owner by default); that
182
- person confirms in the app that it may use their connections.
187
+ - `ekanos teams agents enable <team> <key> [--as <member-email>]
188
+ [--confirm-access]` / `disable <team> <key>` — the app's "Turn on" /
189
+ "Turn off". The agent runs as a team member who manages agents (the
190
+ team's owner by default; with `--confirm-access`, you).
191
+ - `ekanos teams agents confirm <team> <key>` — the person the agent runs as
192
+ confirms, as themselves, that it may use their connections in runs no one
193
+ watches; the output says which products' connections that covers. It
194
+ confirms only the version it printed: a newer publish since is refused, to
195
+ be reviewed and confirmed again. Nobody confirms for anyone else.
183
196
  - `ekanos teams agents pin <team> <key> <version>` / `unpin <team> <key>`.
184
197
  - `ekanos teams agents policy <team> <key>` — every tool the agent can call,
185
198
  read or write, and whether it runs on its own or waits for approval;
186
199
  `… policy <team> <key> set <tool> auto|approve`, `unset <tool>`,
187
200
  `--reads auto|approve --writes auto|approve`. A provided agent's policy
188
201
  follows its template unless the template turns on team overrides for it.
202
+ On any agent, a change that lets more run on its own drops the confirmation
203
+ of the person it runs as, and the agent waits for them to confirm again
204
+ (`--confirm-access` when that person is you).
205
+ - `ekanos teams agents skills <team> <key> [add|remove <skill>]` — the
206
+ skills the agent reads; attach a team skill (pushed with
207
+ `skills push --team`) or a Source one. A provided agent takes them only
208
+ when its template's `teamCustomization.skills` is on; its own stay.
189
209
  - `ekanos teams triggers list|add|remove <team> <key> …` — manual, schedule
190
- (`--cron`, `--timezone`), webhook (URL and token shown once) and
210
+ (`--cron`, `--timezone`), webhook (the token goes to a file only the
211
+ user can read, never the output) and
191
212
  integration events (`event zendesk.ticket_created --filter '{…}'`, or any
192
213
  other id in the product's `agentEvents`, e.g. `event linear.issue_labeled
193
- --filter '{"labels":["feedback"]}'`).
214
+ --filter '{"labels":["feedback"]}'`), plus `slack --channel '#name' [--dms]
215
+ --yes` and `linear [--label <name>]` once the team has installed Slack or
216
+ Ekanos's Linear app with `ekanos teams connect <team> slack|linear-app`.
194
217
  - `ekanos teams links list|add|remove <team> <from-key> [<to-key>] --kind
195
218
  talk|delegate [--mode await|handoff]`.
196
219
  - `ekanos teams mcp list|add|status|token|effect <team> [<server-key> …]` — a
@@ -222,7 +245,7 @@ reviewer's queue.
222
245
  npx @ekanos/cli reviewers list --source <slug> --json
223
246
  npx @ekanos/cli reviewers add <email> --reach source --source <slug>
224
247
  npx @ekanos/cli reviewers add <email> --reach team --team <team-slug> --source <slug>
225
- npx @ekanos/cli reviewers remove <email> [--team <team-slug>] --source <slug>
248
+ npx @ekanos/cli reviewers remove <email> [--team <team-slug>] --source <slug> --yes
226
249
  ```
227
250
 
228
251
  `remove` without `--team` takes the person off at every reach; with it, only
@@ -235,11 +258,11 @@ is refused (`USER_NOT_IN_SOURCE`): `ekanos teams list` shows the teams.
235
258
  |---|---|
236
259
  | Making a product available to a Source; granting seats | Ekanos super admin, in Ekanos's admin |
237
260
  | Building or updating an integration | A developer, with `ekanos validate` / `ekanos publish` |
238
- | Agents provided for every team | A Source admin, with `ekanos agents` |
239
- | Testing an unpublished agent version on one team | A Source admin, with `ekanos agents test <key> --team <slug>` |
261
+ | Agents provided for every team | A Source admin, with `ekanos agents` (`agents archive <key>` retires one once no team has it on) |
262
+ | Testing an unpublished agent version on one team | A Source admin: `ekanos teams agents enable\|pin <team> <key> --draft`, then `ekanos agents test <key> --team <slug>` |
240
263
  | Running a team's agent, reading its runs (transcript, tool calls) | A team's agent manager in the app, or a Source admin with `ekanos runs` |
241
- | Deciding what an agent run waits on (approve, reject, edit & send a reply) | A team's agent manager in the app, or a Source admin with `ekanos approvals` |
242
- | Skills (SKILL.md folders) for every team, or one team's own | A Source admin, with `ekanos skills push` (`--team <slug>` for one team) |
264
+ | Deciding what an agent run waits on (approve, reject, edit & send a reply) | A team's agent manager in the app, or a Source admin with `ekanos approvals` (for a team's own agent, only a Source admin who manages that team's agents) |
265
+ | Skills (SKILL.md folders) for every team, or one team's own | A Source admin, with `ekanos skills push` (`--team <slug>` for one team); `ekanos skills archive` retires one nothing uses |
243
266
  | Knowledge articles for every team (General), or one team's own | A Source admin, with `ekanos knowledge push` (`--team <slug>` for one team); a team's members in the app |
244
267
  | Who decides agent drafts that wait for a person | A Source admin, with `ekanos reviewers` |
245
268
  | An integration's app for the whole Source (client ID and secret) | A Source admin, with `ekanos apps set` at their own terminal |
@@ -248,5 +271,9 @@ is refused (`USER_NOT_IN_SOURCE`): `ekanos teams list` shows the teams.
248
271
  | A team's own app for an integration (client ID, secrets, webhook URL) | The team in the app, or a Source admin with `ekanos teams` |
249
272
  | A provided agent's triggers, links and approvals | A Source admin, in the template (`ekanos agents triggers / links / policy / overrides`); teams change them only where `teamOverrides` allows |
250
273
  | Creating a team, inviting its members, changing their roles | A Source admin, with `ekanos teams create` / `ekanos teams members` (or the team's owner in the app) |
251
- | Connecting an integration (signing in) | Each team, in the app |
274
+ | Connecting an integration for a team (signing in) | A team member in the app, or a Source admin with `ekanos teams connect <team> <product>` (`--as <member-email>` when the connection is a person's own) |
252
275
  | Turning on a provided agent for a team, pinning its version, its triggers, links, MCP servers and approval policy | Each team in the app, or a Source admin with `ekanos teams agents\|triggers\|links\|mcp` |
276
+ | Which products a team sees in the app (product scopes) | A Source admin: `ekanos sources scopes` (and `add`/`remove <scope> <product>`), `ekanos teams scope show\|set <team>`; creating a scope is in /admin |
277
+ | Is a team's agent live, and if not, what is the next step | A Source admin, with `ekanos teams agents show <team> <key>`; the whole team on one screen with `ekanos teams show <team>` |
278
+ | Disconnecting a team's integration, removing a team's MCP server | A Source admin, with `ekanos teams disconnect <team> <product> --yes` / `ekanos teams mcp remove <team> <server-key> --yes`, or the team in the app |
279
+ | Confirming an agent may use a person's connections | Only the person it runs as, signed in as themselves: `ekanos teams agents confirm <team> <key>` (or `enable --confirm-access`, `agents publish --confirm-access`), or **Confirm access** in the app. On a team held on an earlier version (a newer one reaches further than they confirmed) it moves the team to the version waiting |
@@ -116,8 +116,8 @@ import {
116
116
  </div>
117
117
  ```
118
118
 
119
- `Stat` owns the sizes — the heading face, `text-2xl`, `tracking-tight`,
120
- `tabular-nums`, and the arrow glyph that pairs with `StatChange`'s color so
119
+ `Stat` owns the sizes — the `figure` value (heading face, Headline tier,
120
+ tabular), the `text-eyebrow` label, and the arrow glyph that pairs with `StatChange`'s color so
121
121
  the tone never rides on hue alone. Don't override them, and don't rebuild
122
122
  them by hand: a Source that swaps typefaces carries the component, not your
123
123
  spans.