@ekanos/cli 0.15.0 → 0.16.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 (113) hide show
  1. package/README.md +41 -4
  2. package/dist/auth/ekanos-api.d.ts +23 -0
  3. package/dist/auth/ekanos-api.js +33 -6
  4. package/dist/auth/ekanos-api.js.map +1 -1
  5. package/dist/commands/agents.js +3 -2
  6. package/dist/commands/agents.js.map +1 -1
  7. package/dist/commands/apps.d.ts +11 -3
  8. package/dist/commands/apps.js +86 -28
  9. package/dist/commands/apps.js.map +1 -1
  10. package/dist/commands/catalog.d.ts +4 -2
  11. package/dist/commands/catalog.js +166 -35
  12. package/dist/commands/catalog.js.map +1 -1
  13. package/dist/commands/login.d.ts +2 -0
  14. package/dist/commands/login.js +17 -0
  15. package/dist/commands/login.js.map +1 -1
  16. package/dist/commands/runs.d.ts +7 -3
  17. package/dist/commands/runs.js +21 -5
  18. package/dist/commands/runs.js.map +1 -1
  19. package/dist/commands/scope-notice.d.ts +7 -0
  20. package/dist/commands/scope-notice.js +4 -11
  21. package/dist/commands/scope-notice.js.map +1 -1
  22. package/dist/commands/sources-roles.d.ts +5 -0
  23. package/dist/commands/sources-roles.js +235 -0
  24. package/dist/commands/sources-roles.js.map +1 -0
  25. package/dist/commands/sources.d.ts +5 -0
  26. package/dist/commands/sources.js +6 -1
  27. package/dist/commands/sources.js.map +1 -1
  28. package/dist/commands/team-agent-readiness.d.ts +18 -2
  29. package/dist/commands/team-agent-readiness.js +39 -39
  30. package/dist/commands/team-agent-readiness.js.map +1 -1
  31. package/dist/commands/team-agents-agents.d.ts +5 -2
  32. package/dist/commands/team-agents-agents.js +152 -15
  33. package/dist/commands/team-agents-agents.js.map +1 -1
  34. package/dist/commands/team-agents-define.d.ts +31 -0
  35. package/dist/commands/team-agents-define.js +176 -0
  36. package/dist/commands/team-agents-define.js.map +1 -0
  37. package/dist/commands/team-agents-mcp.js +112 -10
  38. package/dist/commands/team-agents-mcp.js.map +1 -1
  39. package/dist/commands/team-agents-triggers.d.ts +1 -1
  40. package/dist/commands/team-agents-triggers.js +137 -5
  41. package/dist/commands/team-agents-triggers.js.map +1 -1
  42. package/dist/commands/team-agents.d.ts +4 -1
  43. package/dist/commands/team-agents.js +17 -4
  44. package/dist/commands/team-agents.js.map +1 -1
  45. package/dist/commands/team-llm-key.d.ts +14 -0
  46. package/dist/commands/team-llm-key.js +122 -0
  47. package/dist/commands/team-llm-key.js.map +1 -0
  48. package/dist/commands/teams-connect.js +123 -31
  49. package/dist/commands/teams-connect.js.map +1 -1
  50. package/dist/commands/teams-lifecycle.d.ts +90 -0
  51. package/dist/commands/teams-lifecycle.js +457 -0
  52. package/dist/commands/teams-lifecycle.js.map +1 -0
  53. package/dist/commands/teams-onboard.d.ts +14 -0
  54. package/dist/commands/teams-onboard.js +62 -13
  55. package/dist/commands/teams-onboard.js.map +1 -1
  56. package/dist/commands/teams-overview.js +6 -2
  57. package/dist/commands/teams-overview.js.map +1 -1
  58. package/dist/commands/teams.d.ts +25 -5
  59. package/dist/commands/teams.js +101 -39
  60. package/dist/commands/teams.js.map +1 -1
  61. package/dist/commands/workflows.d.ts +37 -0
  62. package/dist/commands/workflows.js +589 -0
  63. package/dist/commands/workflows.js.map +1 -0
  64. package/dist/connect-fields.d.ts +22 -0
  65. package/dist/connect-fields.js +115 -0
  66. package/dist/connect-fields.js.map +1 -0
  67. package/dist/context.d.ts +12 -0
  68. package/dist/context.js +32 -9
  69. package/dist/context.js.map +1 -1
  70. package/dist/index.d.ts +13 -0
  71. package/dist/index.js +357 -122
  72. package/dist/index.js.map +1 -1
  73. package/dist/invocation.d.ts +31 -0
  74. package/dist/invocation.js +58 -0
  75. package/dist/invocation.js.map +1 -0
  76. package/dist/runs-api.js +8 -3
  77. package/dist/runs-api.js.map +1 -1
  78. package/dist/safe-fs.d.ts +18 -0
  79. package/dist/safe-fs.js +57 -0
  80. package/dist/safe-fs.js.map +1 -1
  81. package/dist/secret-form.d.ts +48 -0
  82. package/dist/secret-form.js +212 -0
  83. package/dist/secret-form.js.map +1 -0
  84. package/dist/secret-input.d.ts +96 -0
  85. package/dist/secret-input.js +299 -0
  86. package/dist/secret-input.js.map +1 -0
  87. package/dist/team-connect-api.d.ts +78 -3
  88. package/dist/team-connect-api.js +17 -2
  89. package/dist/team-connect-api.js.map +1 -1
  90. package/dist/team-lifecycle-api.d.ts +435 -0
  91. package/dist/team-lifecycle-api.js +301 -0
  92. package/dist/team-lifecycle-api.js.map +1 -0
  93. package/dist/teams-api.d.ts +13 -1
  94. package/dist/teams-api.js +88 -27
  95. package/dist/teams-api.js.map +1 -1
  96. package/dist/unknown-command.d.ts +18 -0
  97. package/dist/unknown-command.js +50 -0
  98. package/dist/unknown-command.js.map +1 -0
  99. package/dist/workflows-api.d.ts +69 -0
  100. package/dist/workflows-api.js +182 -0
  101. package/dist/workflows-api.js.map +1 -0
  102. package/package.json +3 -3
  103. package/templates/AGENTS.md.tmpl +6 -4
  104. package/templates/claude-skill.md.tmpl +4 -1
  105. package/templates/package.json.tmpl +4 -4
  106. package/templates/skills/build-agent/SKILL.md +43 -10
  107. package/templates/skills/build-agent/references/agent-json.md +4 -1
  108. package/templates/skills/build-agent/references/app-setup.md +14 -7
  109. package/templates/skills/build-agent/references/rollout.md +26 -2
  110. package/templates/skills/build-agent/references/set-up-an-integration.md +46 -29
  111. package/templates/skills/build-integration/references/widget-design.md +1 -1
  112. package/templates/skills/ekanos-platform/SKILL.md +66 -14
  113. package/templates/skills/polish-widgets/references/patterns.md +3 -3
@@ -39,9 +39,15 @@ installed — so check it, every time (§ 4, "Make it reachable").
39
39
  ## Hard rules
40
40
 
41
41
  - Never ask for, accept or write a secret (API key, client secret, webhook
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.
42
+ signing secret), and never read one from a file or a variable yourself.
43
+ The user enters it, and it never passes through you: run the command with
44
+ `--browser` (`apps set`, `apps connect`, `teams app set`, `teams connect`,
45
+ `teams mcp token`, `teams llm-key set` take it) and the CLI opens a
46
+ one-time form in their browser on this computer — tell them to fill it in
47
+ there. If they would rather, they put it in an environment variable or a
48
+ file only they can read, and you pass `--secret-env <NAME>` or
49
+ `--secret-file <path>`. Or they type it at their own terminal, or a team
50
+ enters it in the Ekanos app. A secret is never a value on the command line.
45
51
  - Never `publish`, `rollback` or `archive` without the user's explicit yes to
46
52
  that version or agent, after they have seen it. `--yes` records that
47
53
  consent; it is never a way past a question.
@@ -105,7 +111,8 @@ list` to find the role holding `agents.review` for reviewers — see the
105
111
  `ekanos-platform` skill, "Onboarding a team"), and send the member who will
106
112
  sign in the link from `ekanos teams connect <team> <product>`. For the
107
113
  Source's app itself, `references/app-setup.md` has the console walk-through.
108
- Secrets are only ever entered at the user's terminal or in the app.
114
+ Secrets are only ever entered by the user — in the `--browser` form, at
115
+ their terminal, or in the app — never through you.
109
116
 
110
117
  ## 2. The interview
111
118
 
@@ -208,6 +215,32 @@ in parentheses are the recommendation when the user has no preference.
208
215
  team pilots
209
216
  it first, and do § 4 with them.
210
217
 
218
+ ## 3b. Only one team, or only the user: a team's own or a personal agent
219
+
220
+ When the agent is for one team only, or for the user alone (§ 2's rollout
221
+ question, `references/rollout.md`), skip the template: the same files make a
222
+ team's own agent, or with `--personal` the user's own.
223
+
224
+ 1. On their go: `npx @ekanos/cli teams agents create <team> --from agents/<key> --source <slug> --json`
225
+ (add `--personal` for the user's own). The user becomes its creator, so
226
+ they must be an active member of that team; a `NOT_A_TEAM_MEMBER` refusal
227
+ names the command that adds them. Skill folders beside it are pushed as
228
+ that team's skills. Drop any field only a template has (exit 3 lists them).
229
+ 2. It starts as a draft:
230
+ `npx @ekanos/cli teams agents enable <team> <key> --source <slug> --json`.
231
+ Confirm what it may use only with the user's yes (`--confirm-access` on
232
+ `create` or `enable`, or `teams agents confirm <team> <key>`); a personal
233
+ agent's creator alone may.
234
+ 3. Start it from a schedule or a webhook:
235
+ `npx @ekanos/cli teams triggers add <team> <key> schedule --cron "0 8 * * 1-5" --timezone <zone> --prompt "…" --json`
236
+ or `… webhook --prompt "…"`. The webhook's token is saved to a file only
237
+ the user can read — never open or print it; tell them a personal agent's
238
+ token lets whoever holds it make the agent act as them.
239
+ 4. Later changes: edit the files and
240
+ `npx @ekanos/cli teams agents apply <team> agents/<key> --base-version <n> --json`
241
+ (`<n>` from `teams agents show`). Never `--overwrite` a conflict you have
242
+ not shown the user.
243
+
211
244
  ## 4. Make it reachable, and prove it end to end
212
245
 
213
246
  For each team that turns on an agent with a channel trigger, start with
@@ -225,12 +258,12 @@ screen). For the detail behind it:
225
258
  and `agent` (`credentialsSaved`, `connected` = installed, `neededBy`),
226
259
  and the `agent-events` webhook in `teamApps[].webhooks` must have an
227
260
  `endpoint`. Read the state back to the user in those words.
228
- 3. Not installed: the user runs, **in their own terminal** (it asks for the
229
- Linear app's secrets, which you never handle):
230
- `npx @ekanos/cli teams connect <team> linear --connection agent --source <slug>`.
231
- It asks for the app's client ID, secret and webhook signing secret if
232
- missing, opens the install (a Linear workspace admin approves it) and
233
- waits. No webhook URL yet: `npx @ekanos/cli teams webhook <team> linear
261
+ 3. Not installed: run
262
+ `npx @ekanos/cli teams connect <team> linear --connection agent --browser --source <slug>`
263
+ (or the user runs it without `--browser` in their own terminal). If the
264
+ app's client ID, secret or webhook signing secret is missing, it opens a
265
+ form in the user's browser for them to fill — you never handle those —
266
+ then opens the install (a Linear workspace admin approves it) and waits. No webhook URL yet: `npx @ekanos/cli teams webhook <team> linear
234
267
  agent-events --source <slug>` (shown once, and saved to a file only the
235
268
  user can read — the output names it; the user copies it into the Linear
236
269
  app. Never open or print that file yourself).
@@ -56,7 +56,10 @@ conflicting change unless `--overwrite`. Unknown fields are refused.
56
56
  ```
57
57
 
58
58
  The tool names above are illustrations. Take real ones from
59
- `ekanos catalog --json`.
59
+ `ekanos catalog --json`; `ekanos catalog <product> --json` gives each tool's
60
+ `inputSchema` (when a tool needs an id, another tool of the product returns
61
+ it) and the product's `connection` (`connectedBy`, `runsUse`,
62
+ `sourceConnection`).
60
63
 
61
64
  ## Fields
62
65
 
@@ -41,23 +41,30 @@ working from those rather than from Ekanos.
41
41
  the provider's docs rather than guessing.
42
42
  - The last console step is always "copy the client ID and the secret".
43
43
  **Never ask them to paste the secret into the chat.** For the Source's app,
44
- have them run, **in their own terminal**:
44
+ run this yourself, and tell them a form is opening in their browser:
45
45
 
46
46
  ```bash
47
- npx @ekanos/cli apps set <product> --source <slug>
47
+ npx @ekanos/cli apps set <product> --browser --source <slug>
48
48
  ```
49
49
 
50
- It asks for the client ID, then the secret with hidden input; Enter keeps
51
- a saved value, so either can be changed on its own. For a team's
52
- app, they enter the fields in the team's setup panel in the Ekanos app.
50
+ The form asks for the client ID and the secret; a field left empty keeps
51
+ its saved value, so either can be changed on its own. What they type goes
52
+ from their browser to the CLI and on to Ekanos, never to you. (Or they run
53
+ `npx @ekanos/cli apps set <product> --source <slug>` in their own terminal,
54
+ which asks with hidden input.) For a team's app,
55
+ `npx @ekanos/cli teams app set <team> <product> --browser --source <slug>`
56
+ does the same, or they enter the fields in the team's setup panel in the
57
+ Ekanos app.
53
58
  - Then check: `apps show <product> --source <slug> --json` should say
54
59
  `configured: true`, and the catalog's step should be `done`. Tell them
55
60
  teams can now connect, and what the team-side steps are.
56
61
 
57
62
  ## When it goes wrong
58
63
 
59
- - `apps set` says it needs a terminal: it was run inside Claude or a script.
60
- Ask them to run it in a terminal tab themselves.
64
+ - `apps set` says there is no terminal to ask at: add `--browser`. If
65
+ `--browser` is refused (CI, SSH, no display), ask them to run it in a
66
+ terminal tab themselves. The form gives up after five minutes; run it
67
+ again for a fresh one.
61
68
  - `apps set` asks which host: they are signed in to more than one Ekanos;
62
69
  add `--host <url>` (the Source's site) or log out of the other.
63
70
  - Sign-in later fails with a redirect mismatch: the app is missing one of the
@@ -65,11 +65,35 @@ plan is ready.
65
65
 
66
66
  ## A team's own agent
67
67
 
68
- Built by a team in the app (Agents → New). Only that team has it; the Source
69
- cannot update or roll it back, and nothing about it is visible to other teams.
68
+ Built for one team, in the app (Agents → New) or from the terminal with the
69
+ same `agent.json` a template uses:
70
+ `ekanos teams agents create <team> --from agents/<key>` (then
71
+ `ekanos teams agents enable <team> <key>` — it starts as a draft), and
72
+ `ekanos teams agents apply <team> agents/<key> --base-version <n>` to change
73
+ it from the file later. Only that team has it; the Source cannot update or
74
+ roll it back, and nothing about it is visible to other teams. Whoever creates
75
+ it is its creator — its tools run as them — so they must be a member of the
76
+ team who manages its agents. A field only a template has (`connections`,
77
+ `mcpServers`, `teamCustomization`, `triggers`, `links`, `teamOverrides`) is
78
+ refused; add triggers with `ekanos teams triggers add`.
70
79
 
71
80
  Good for: one team's own process; experiments a team owns.
72
81
 
82
+ ## A personal agent
83
+
84
+ One person's agent for themselves: `ekanos teams agents create <team> --from
85
+ agents/<key> --personal`, by a member of that team. It acts for its creator,
86
+ with their own connections, on every trigger, so it is theirs alone: nobody
87
+ else changes it, runs it, decides its approvals or cancels its runs — not a
88
+ team manager, not the Source admin (`PERSONAL_AGENT_CREATOR_ONLY`). Others see
89
+ that it exists, not what its runs read or did. It starts from a schedule or a
90
+ webhook (`ekanos teams triggers add <team> <key> schedule --cron "…" --prompt
91
+ "…"`); whoever holds its webhook token can make it act as its creator, so the
92
+ token goes to a file only they can read, never into a chat.
93
+
94
+ Good for: "brief me on my day", "draft replies to my inbox" — one person's
95
+ own work on their own accounts.
96
+
73
97
  ## Questions that decide it
74
98
 
75
99
  - How many teams do this work? The same way?
@@ -60,19 +60,32 @@ connect nothing for it.
60
60
  `teams show` (or `catalog`) and say what changed ("Ekanos sees the client ID
61
61
  and secret now"). If the check disagrees with what they said, look at the
62
62
  difference with them; don't move on.
63
- - **Secrets never pass through the chat.** Client secrets and signing
64
- secrets go in at the user's own terminal (`ekanos apps set`,
65
- `ekanos teams app set`, with hidden input) or in the team's page in the app.
66
- If they paste one into the chat anyway, tell them to rotate it in the
67
- provider's console and enter the new one at the terminal.
68
- - **Connect with `teams connect <team> <product>`, run by the user in their
69
- own terminal.** It does whatever the integration needs: asks a form's fields
63
+ - **Secrets never pass through the chat, or through you.** Client secrets
64
+ and signing secrets go in through a form in the user's browser that you
65
+ start with `--browser` (`ekanos apps set <product> --browser`,
66
+ `ekanos teams app set <team> <product> --browser`), at the user's own
67
+ terminal with hidden input, or in the team's page in the app. Never read
68
+ one from a file or an environment variable yourself; if the user has put
69
+ one there, pass its name with `--secret-env <NAME>` or its path with
70
+ `--secret-file <path>` and let the CLI read it. If they paste one into the
71
+ chat anyway, tell them to rotate it in the provider's console and enter
72
+ the new one through the form.
73
+ - **Connect with `teams connect <team> <product>`** — add `--browser` when
74
+ you run it, so any field it needs opens as a form in the user's browser;
75
+ without it the user runs it in their own terminal. It does whatever the
76
+ integration needs: asks a form's fields
70
77
  (secrets hidden), runs the team-app prompts first when the team's own app is
71
78
  missing, or opens a one-time sign-in link and waits until the team is
72
- connected. The provider's consent is still a person's click, by a member of
73
- the team (owner/admin for a team-wide connection): the user when they are
74
- one, else `--as <email>` prints a link to send that member. `--link-only`
75
- prints just the team's page. Tell them who should sign in: the account the
79
+ connected. Non-secret fields of any type can be passed with
80
+ `--set <field>=<value>` (a list as `a,b`; secrets and JSON values only at a prompt), so
81
+ it also runs in a script; optional ones can be left out. The provider's
82
+ consent is still a person's click, by a member of the team (owner/admin for
83
+ a team-wide connection): the user when they are one, else `--as <email>`
84
+ prints a link to send that member. A Source admin who is not on the team
85
+ joins it first with `ekanos teams members add <team> --self` (no email). A
86
+ personal product (each person connects their own, such as ROAM) connects
87
+ the account of whoever runs `teams connect`. `--link-only` prints just the
88
+ team's page. Tell them who should sign in: the account the
76
89
  integration acts as. If the product is not enabled for the Source, a
77
90
  super-admin enables it (`sources products` shows what the Source has). A dedicated seat such as "Support agent" makes its replies easy
78
91
  to recognise.
@@ -88,11 +101,12 @@ pilot), the team-side steps can be done from the CLI:
88
101
  1. `npx @ekanos/cli teams show <team> <product> --source <slug>`: the
89
102
  callback URL to register and the integration's steps.
90
103
  2. They create the app in the provider's console, step by step as above.
91
- 3. **In their own terminal:**
92
- `npx @ekanos/cli teams app set <team> <product> --source <slug>`. It asks
93
- for each field and hides the secret ones; Enter keeps a saved value. It
94
- refuses to run inside Claude; that is deliberate. To change one value
95
- later, they need not re-enter the rest:
104
+ 3. Run `npx @ekanos/cli teams app set <team> <product> --browser --source <slug>`
105
+ and tell them a form is opening in their browser: it has every field,
106
+ secrets as password inputs, and a field left empty keeps its saved value.
107
+ What they type never reaches you. (Without `--browser`, they run it in
108
+ their own terminal, which asks for each field and hides the secret ones.)
109
+ To change one value later, they need not re-enter the rest:
96
110
  `teams app set <team> <product> --field <name>` asks for just that field
97
111
  (names are in brackets in `teams show`), `--set <name>=<value>` sets a
98
112
  non-secret field (a subdomain, a client ID) without a prompt — you may run
@@ -122,10 +136,11 @@ mentions arrive. When the agent has any Linear trigger:
122
136
  redirect URIs, webhooks on with **Agent session events** and **Issues**.
123
137
  3. Its webhook URL: `teams webhook <team> linear agent-events` (once; paste
124
138
  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
139
+ 4. `npx @ekanos/cli teams connect <team> linear --connection agent --browser --source <slug>`
140
+ — opens a form in the user's browser for the client ID, secret and
141
+ webhook signing secret if any is missing (without `--browser`, the user
142
+ runs it in their own terminal and it asks there), opens the install for a
143
+ Linear workspace admin to approve, and
129
144
  waits until it is installed. (`teams connect <team> linear` with no
130
145
  `--connection` offers this itself once the personal connection is made,
131
146
  when the team has agents with Linear triggers.)
@@ -146,11 +161,12 @@ the Source's connection.
146
161
  1. **Connect, once, as the Source.** For an integration where each customer
147
162
  brings its own app (Zendesk), first create that app in the shared account,
148
163
  exactly as in the worked example below (OAuth client, Confidential), but
149
- once, for the Source. Then, **in their own terminal**:
150
- `npx @ekanos/cli apps connect <product> --source <slug>`. It asks for the
164
+ once, for the Source. Then run
165
+ `npx @ekanos/cli apps connect <product> --browser --source <slug>` (or the
166
+ user runs it without `--browser` in their own terminal). It asks for the
151
167
  app's fields it doesn't have yet (Zendesk: subdomain, client ID, client
152
- secret, webhook signing secret; secrets hidden, never as flags, and it
153
- refuses to run inside Claude), prints the redirect URL to register and the
168
+ secret, webhook signing secret) in a form in the user's browser — never
169
+ through you, never as values on the command line — prints the redirect URL to register and the
154
170
  consent link, then waits up to ten minutes until it is connected. Whoever
155
171
  clicks the link is the account the integration acts as for every team, so
156
172
  suggest a dedicated seat ("Support agent"). `apps list` shows every
@@ -201,9 +217,9 @@ from `teams show zendesk`.
201
217
  Center › Apps and integrations › Webhooks › Create webhook › Trigger or
202
218
  automation: that URL, POST, JSON, no authentication. Open it and Reveal
203
219
  secret.
204
- 3. **Credentials into Ekanos.** `ekanos teams app set <team> zendesk` in
205
- their terminal: subdomain, client ID, client secret, webhook signing
206
- secret. Any of them can be entered or changed later on its own
220
+ 3. **Credentials into Ekanos.** `ekanos teams app set <team> zendesk --browser`
221
+ (a form in their browser; or without `--browser`, in their terminal):
222
+ subdomain, client ID, client secret, webhook signing secret. Any of them can be entered or changed later on its own
207
223
  (`--field <name>`); `teams show` says which are saved.
208
224
  4. **Connect.** `npx @ekanos/cli teams connect <team> zendesk --source <slug>`
209
225
  opens the sign-in and waits; whoever approves it should be the Zendesk
@@ -244,5 +260,6 @@ from `teams show zendesk`.
244
260
  not installed for this team", or no webhook URL) and the command that
245
261
  fixes it. Installed and still silent: the Linear app's webhook must send
246
262
  **Agent session events** to the latest URL from `teams webhook`.
247
- - **A command says it needs a terminal:** it was run inside Claude. Ask them
248
- to run it in a terminal tab themselves.
263
+ - **A command says there is no terminal to ask at:** run it again with
264
+ `--browser`. If `--browser` is refused (CI, SSH, no display), ask them to
265
+ run it in a terminal tab themselves.
@@ -185,7 +185,7 @@ mock switch) so the harness can show all four; remove it before publish.
185
185
  `border-border`, `bg-primary`, `text-destructive`. NEVER raw palette
186
186
  classes (`bg-white`, `text-gray-500`, `bg-amber-400`) or hex/oklch
187
187
  literals — they break in dark mode and off-brand tenants.
188
- - **Accent discipline**: the primary (coral-orange) on ≤10% of the widget —
188
+ - **Accent discipline**: the `primary` token (the Source's accent) on ≤10% of the widget —
189
189
  one CTA, one highlighted value, one active state. Semantic status colors
190
190
  (success/warning/destructive) are not accents.
191
191
  - **Depth via shadow, not borders** where a surface needs lift.
@@ -54,6 +54,7 @@ npx @ekanos/cli teams members invite bank-a raj@bank-a.com --role admin # defa
54
54
  npx @ekanos/cli teams members list bank-a # members and pending invitations
55
55
  npx @ekanos/cli teams members role bank-a raj@bank-a.com member
56
56
  npx @ekanos/cli teams members remove bank-a raj@bank-a.com --yes
57
+ npx @ekanos/cli teams members resend bank-a lee@bank-a.com # resend, or renew an expired invitation
57
58
  npx @ekanos/cli teams connect bank-a zendesk # connect it for the team (asks, signs in, waits)
58
59
  npx @ekanos/cli teams connect bank-a linear --as raj@bank-a.com # a sign-in link for raj
59
60
  npx @ekanos/cli sources products # what the Source has enabled (super-admin enables)
@@ -68,10 +69,13 @@ npx @ekanos/cli sources products # what the Source h
68
69
  - Roles are the team roles (owner / admin / member, or the Source's own
69
70
  customized ones). Pick a reviewer for agents by the role holding
70
71
  `agents.review` in `teams roles list`. The primary owner's role cannot be
71
- changed here; ownership moves in the app.
72
+ changed here; ownership moves in the app. The Source's custom roles
73
+ themselves are `sources roles` (`create|update|delete`; owner, admin and
74
+ member are fixed).
72
75
  - `teams connect <team> <product>` does the connect: it asks a form's fields
73
- at the user's terminal (hidden for secrets — so the user runs it, never you
74
- with values), runs the team-app prompts first when needed (Zendesk), or
76
+ at the user's terminal (hidden for secrets) or, run by you with
77
+ `--browser`, in a one-time form in the user's browser — never with values
78
+ from you — runs the team-app prompts first when needed (Zendesk), or
75
79
  opens a one-time sign-in link and waits. The person who signs in is a team
76
80
  member (owner/admin for a team-wide connection): the user when they are
77
81
  one, else `--as <email>` prints a link to send that member. `--no-wait`,
@@ -81,6 +85,17 @@ npx @ekanos/cli sources products # what the Source h
81
85
  what it has. Enabling one is a super-admin grant (`sources products enable`)
82
86
  that an `ekanos login` session cannot make — the super-admin does it in
83
87
  /admin.
88
+ - The rest of a team's life: `teams leave <team> --yes` (the user's own
89
+ membership), `teams groups list|create|update|delete|members` (groups
90
+ narrow what their members see to `--products a,b`), `teams health <team>
91
+ [<product>] [--run]` (each connected integration's health; `--run` checks
92
+ one now; `<product> --mine` the user's own personal connection),
93
+ `teams workspace list|default <team> [<workspace>]`, and
94
+ `sources people` (everyone on the Source and their teams). Each one that
95
+ takes something away needs `--yes` when you run it, which you pass only
96
+ after the user says so. Transferring a team's ownership and deleting a team
97
+ are not in the CLI: the primary owner does them in the app, confirmed by a
98
+ code emailed to them.
84
99
 
85
100
  ## Products: integrations and experiences
86
101
 
@@ -136,8 +151,8 @@ connect (`setupSteps` step `provider-app`). It is the Source's own app — for a
136
151
  white-label Source, under its product name and company — and its admin
137
152
  creates it once in the provider's console. The integration ships the steps
138
153
  (the catalog's `instructions`, with the Source's exact callback URLs filled
139
- in); `ekanos apps set <product>`, run by the admin at their own terminal,
140
- takes the client ID and secret. The `build-agent` skill walks through it
154
+ in); `ekanos apps set <product>` takes the client ID and secret — at the
155
+ admin's own terminal, or in a browser form when you run it with `--browser`. The `build-agent` skill walks through it
141
156
  (`references/app-setup.md`). Integrations whose teams each bring their own
142
157
  app (Zendesk) have no Source app; each team follows that app's steps.
143
158
 
@@ -158,8 +173,13 @@ changed through the CLI or the app, with no deploy.
158
173
  (links) and which calls wait for approval, and — per area, with
159
174
  `teamOverrides` — whether a team may change them. The template wins unless
160
175
  an area is opened to teams.
161
- - **A team's own** — built by a team in the app (Agents → New). Only that team
162
- has it, and the Source cannot update it.
176
+ - **A team's own** — built for one team, in the app (Agents → New) or with
177
+ `ekanos teams agents create <team> --from <dir>` from the same `agent.json`.
178
+ Only that team has it, and the Source cannot update it.
179
+ - **A personal agent** — one member's own (`--personal`, or "Just you" in the
180
+ app). It acts for its creator, with their own connections, on every trigger,
181
+ so only they change it, run it, decide its approvals or cancel its runs —
182
+ not a team manager and not the Source admin.
163
183
 
164
184
  Skills are folders (`SKILL.md` + references) an agent loads when needed.
165
185
  A Source admin pushes them with `ekanos skills push <dir>`: at Source level
@@ -183,11 +203,23 @@ always `ekanos teams <area> <verb> <team> …`:
183
203
 
184
204
  - `ekanos teams agents list <team>` — provided agents, on or off, the version
185
205
  each runs (pinned or following), triggers, links, the team's MCP servers,
186
- and what each still needs connected.
206
+ and what each still needs connected; then the team's own and personal
207
+ agents and whose each is.
208
+ - `ekanos teams agents create <team> --from <dir> [--personal]` /
209
+ `apply <team> <dir> [--base-version <n>]` — the team's own agent, or your
210
+ own, from an `agent.json` (+ `AGENT.md`, + `skills/<slug>/`). You become
211
+ its creator, so you must be an active member of the team. It starts as a
212
+ draft; `enable` turns it on.
187
213
  - `ekanos teams agents enable <team> <key> [--as <member-email>]
188
214
  [--confirm-access]` / `disable <team> <key>` — the app's "Turn on" /
189
215
  "Turn off". The agent runs as a team member who manages agents (the
190
- team's owner by default); `--confirm-access` also confirms it, as you.
216
+ team's owner by default): that member is its creator, whose personal
217
+ connections it uses. Who it runs as is chosen once, when it is turned
218
+ on; to change it, archive it and turn it on again with `--as`.
219
+ `--confirm-access` also confirms it, as you.
220
+ - `ekanos teams agents archive <team> <key> [--yes]` / `unarchive <team>
221
+ <key>` — the app's Archive: off the team's list, nothing starts it, its
222
+ runs and setup kept; `unarchive` brings it back paused, for `enable`.
191
223
  - `ekanos teams agents confirm <team> <key>` — you confirm, as yourself,
192
224
  that the agent may use its connections (the person it runs as's) in runs
193
225
  no one watches; the output says which products' connections that covers.
@@ -208,6 +240,9 @@ always `ekanos teams <area> <verb> <team> …`:
208
240
  skills the agent reads; attach a team skill (pushed with
209
241
  `skills push --team`) or a Source one. A provided agent takes them only
210
242
  when its template's `teamCustomization.skills` is on; its own stay.
243
+ - `ekanos teams agents tags <team> <key> [add|remove <tag>]` — labels that
244
+ organize the team's agents and grant nothing; `add` makes a tag the team
245
+ does not have yet.
211
246
  - `ekanos teams triggers list|add|remove <team> <key> …` — manual, schedule
212
247
  (`--cron`, `--timezone`), webhook (the token goes to a file only the
213
248
  user can read, never the output) and
@@ -216,12 +251,25 @@ always `ekanos teams <area> <verb> <team> …`:
216
251
  --filter '{"labels":["feedback"]}'`), plus `slack --channel '#name' [--dms]
217
252
  --yes` and `linear [--label <name>]` once the team has installed Slack or
218
253
  Ekanos's Linear app with `ekanos teams connect <team> slack|linear-app`.
254
+ - `ekanos teams triggers enable|disable <team> <key> <trigger-id|key>` and
255
+ `edit <team> <key> <trigger-id|key> [--prompt …] [--cron … --timezone …]
256
+ [--filter …] [--channel …] [--dms] [--label …]` — turn a trigger off
257
+ without removing it, or change it in place: a webhook keeps its URL and
258
+ token (only `rotate` makes a new one).
219
259
  - `ekanos teams links list|add|remove <team> <from-key> [<to-key>] --kind
220
260
  talk|delegate [--mode await|handoff]`.
221
261
  - `ekanos teams mcp list|add|status|token|effect <team> [<server-key> …]` — a
222
262
  team's own MCP server (`--url`, `--auth none|token|oauth`); a token is typed
223
- at the admin's terminal with hidden input, never in chat or arguments; OAuth
224
- prints a link for a team member to open.
263
+ at the admin's terminal with hidden input, or in the `--browser` form, never
264
+ in chat or arguments; OAuth prints a link for a team member to open.
265
+ `ekanos teams mcp attach|detach <team> <server-key> <agent-key>` gives one
266
+ agent a team server, or takes it away (where its template allows), and
267
+ `refresh <team> <server-key>` (or `--agent <key>`) lists its tools again.
268
+ - `ekanos teams llm-key show|set|remove <team>` — the team's own Anthropic
269
+ key, which its agents and assistant then use instead of the Source's.
270
+ `show` gives only whether one is saved and its last four characters; `set`
271
+ takes it like any secret (`--browser`, or `--secret-env <NAME>` /
272
+ `--secret-file <path>` the user prepared); `remove` needs `--yes`.
225
273
 
226
274
  Triggers, links and the policy of a provided agent follow its template by
227
275
  default; when the template has not turned on team overrides for that area,
@@ -263,19 +311,23 @@ is refused (`USER_NOT_IN_SOURCE`): `ekanos teams list` shows the teams.
263
311
  | Agents provided for every team | A Source admin, with `ekanos agents` (`agents archive <key>` retires one once no team has it on) |
264
312
  | 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>` |
265
313
  | 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` |
266
- | 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) |
314
+ | Deciding what an agent run waits on (approve, reject, edit & send a reply) | A team's agent manager in the app, or with `ekanos approvals`: a Source admin (for a team's own agent, only one who manages that team's agents), or any seat holder with that authority themselves — a member who manages (or, for reply drafts, reviews) the team's agents, a named reviewer, a personal agent's creator |
315
+ | A team's workflows: saving one, turning it on, running it, deciding its approval gates | A team member who configures integrations, in the app's editor; or a Source admin with `ekanos workflows apply\|enable\|run\|approvals --team <slug>` (Workflows must be on for the Source; a member's personal workflow is theirs alone). Custom Code that writes or reaches a host is approved by whoever turns the workflow on: `ekanos workflows enable <workflow> --team <slug> --confirm-access` |
267
316
  | 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 |
268
317
  | 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 |
269
318
  | Who decides agent drafts that wait for a person | A Source admin, with `ekanos reviewers` |
270
- | An integration's app for the whole Source (client ID and secret) | A Source admin, with `ekanos apps set` at their own terminal |
319
+ | An integration's app for the whole Source (client ID and secret) | A Source admin, with `ekanos apps set` (at their own terminal, or its `--browser` form) |
271
320
  | One connection for the whole Source, used by provided agents in every team | A Source admin, with `ekanos apps connect` (status: `ekanos apps show`), or **Shared integrations › Connections** in the Source admin area |
272
321
  | Which team gets which events on that connection (Zendesk organization → team) | A Source admin, with `ekanos routes` (`webhook`, `options`, `set`, `list`, `remove`, `unrouted`, `replay`), or **Shared integrations › Routing** in the Source admin area |
273
322
  | 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` |
274
323
  | 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 |
275
324
  | 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) |
325
+ | A team's groups and default workspace | A Source admin, with `ekanos teams groups` / `ekanos teams workspace default`, or the team's owner in the app |
326
+ | Transferring a team's ownership, deleting a team | The team's primary owner in the app (a code emailed to them confirms it), or a super-admin under /admin |
327
+ | The Source's custom roles and their permissions | A Source admin, with `ekanos sources roles`; owner, admin and member are fixed |
276
328
  | 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) |
277
329
  | 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` |
278
330
  | 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 |
279
331
  | 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>` |
280
- | 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 |
332
+ | 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. A personal connection: only its owner, `ekanos teams disconnect <team> <product> --mine --yes` |
281
333
  | Confirming an agent may use its connections | Whoever sets it up, as themselves: the Source admin with `ekanos teams agents confirm <team> <key>` (or `enable --confirm-access`, `agents publish --confirm-access`), or a team manager with **Confirm access** in the app — never a plain member. A publish is the confirmation for following teams: no team is held on an earlier version |
@@ -184,7 +184,7 @@ is not information-rich; it is unreadable.
184
184
  <div className="space-y-1 p-2">
185
185
  {events.map((e) => (
186
186
  <div key={e.id} className="flex gap-1 text-xs">
187
- <Icon name="fa-light fa-bolt" className="h-3 w-3" />
187
+ <Icon name="fa-bolt" className="h-3 w-3" />
188
188
  <span>{e.title}</span>
189
189
  </div>
190
190
  ))}
@@ -268,7 +268,7 @@ import {
268
268
  <DropdownMenuTrigger
269
269
  render={<Button variant="ghost" size="icon" className="h-8 w-8" />}
270
270
  >
271
- <Icon name="fa-light fa-ellipsis-vertical" className="h-4 w-4" />
271
+ <Icon name="fa-ellipsis-vertical" className="h-4 w-4" />
272
272
  </DropdownMenuTrigger>
273
273
  <DropdownMenuContent align="end">
274
274
  <DropdownMenuItem>View details</DropdownMenuItem>
@@ -293,7 +293,7 @@ said, and it matches every other widget on the board:
293
293
  ```tsx
294
294
  // AFTER — the SDK's empty state, one sentence of what appears here
295
295
  <Widget.Empty
296
- icon="fa-light fa-inbox"
296
+ icon="fa-inbox"
297
297
  title="No invoices yet"
298
298
  description="Invoices appear here as soon as your first one is issued."
299
299
  />