@ekanos/cli 0.11.0 → 0.13.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 (57) hide show
  1. package/dist/apps-api.d.ts +3 -2
  2. package/dist/apps-api.js +1 -5
  3. package/dist/apps-api.js.map +1 -1
  4. package/dist/commands/agents-edit.js +1 -1
  5. package/dist/commands/agents-edit.js.map +1 -1
  6. package/dist/commands/apps.d.ts +19 -6
  7. package/dist/commands/apps.js +366 -43
  8. package/dist/commands/apps.js.map +1 -1
  9. package/dist/commands/knowledge.d.ts +37 -0
  10. package/dist/commands/knowledge.js +364 -0
  11. package/dist/commands/knowledge.js.map +1 -0
  12. package/dist/commands/routes.d.ts +23 -0
  13. package/dist/commands/routes.js +277 -0
  14. package/dist/commands/routes.js.map +1 -0
  15. package/dist/commands/sources.d.ts +4 -0
  16. package/dist/commands/sources.js +115 -1
  17. package/dist/commands/sources.js.map +1 -1
  18. package/dist/commands/team-agents-triggers.js +2 -1
  19. package/dist/commands/team-agents-triggers.js.map +1 -1
  20. package/dist/commands/teams-connect.d.ts +25 -0
  21. package/dist/commands/teams-connect.js +242 -0
  22. package/dist/commands/teams-connect.js.map +1 -0
  23. package/dist/commands/teams-onboard.d.ts +5 -2
  24. package/dist/commands/teams-onboard.js +12 -40
  25. package/dist/commands/teams-onboard.js.map +1 -1
  26. package/dist/commands/teams.d.ts +60 -5
  27. package/dist/commands/teams.js +141 -46
  28. package/dist/commands/teams.js.map +1 -1
  29. package/dist/connections-api.d.ts +125 -0
  30. package/dist/connections-api.js +156 -0
  31. package/dist/connections-api.js.map +1 -0
  32. package/dist/index.js +90 -6
  33. package/dist/index.js.map +1 -1
  34. package/dist/knowledge-api.d.ts +129 -0
  35. package/dist/knowledge-api.js +138 -0
  36. package/dist/knowledge-api.js.map +1 -0
  37. package/dist/routes-api.d.ts +105 -0
  38. package/dist/routes-api.js +147 -0
  39. package/dist/routes-api.js.map +1 -0
  40. package/dist/source-products-api.d.ts +59 -0
  41. package/dist/source-products-api.js +113 -0
  42. package/dist/source-products-api.js.map +1 -0
  43. package/dist/team-connect-api.d.ts +244 -0
  44. package/dist/team-connect-api.js +95 -0
  45. package/dist/team-connect-api.js.map +1 -0
  46. package/dist/teams-api.d.ts +1 -0
  47. package/dist/teams-api.js +1 -1
  48. package/dist/teams-api.js.map +1 -1
  49. package/package.json +2 -2
  50. package/templates/package.json.tmpl +4 -4
  51. package/templates/skills/build-agent/SKILL.md +18 -3
  52. package/templates/skills/build-agent/references/agent-json.md +29 -8
  53. package/templates/skills/build-agent/references/app-setup.md +2 -1
  54. package/templates/skills/build-agent/references/set-up-an-integration.md +76 -10
  55. package/templates/skills/build-agent/references/skills.md +7 -4
  56. package/templates/skills/build-agent/references/triggers.md +44 -15
  57. package/templates/skills/ekanos-platform/SKILL.md +40 -8
@@ -49,6 +49,15 @@ every `hint`. Look things up in the `ekanos-sdk-docs` MCP server
49
49
  `provider-app`) is not set up, so no team can connect. Offer to walk them
50
50
  through it now — `references/app-setup.md` — or after the interview. The
51
51
  agent can be drafted while it is pending.
52
+ - **Docs and know-how with no home yet** — when the user asks where the
53
+ agent's docs, policies or FAQs should live, offer **Knowledge** first:
54
+ Ekanos's own knowledge base, nothing to sign up for. One collection per
55
+ team plus the Source's General one; load a folder of markdown with
56
+ `ekanos knowledge push <dir> [--team <team>]`, check with
57
+ `ekanos knowledge search "<words>" --team <team>`, and grant the agent
58
+ `search_knowledge` + `read_knowledge_article` (`references/agent-json.md`
59
+ → `tools`). Keep skills for how-to-work instructions; Knowledge for the
60
+ facts the agent looks up.
52
61
  - **Missing** — no product does it. Say so plainly. Options: build the
53
62
  integration (the `build-integration` skill), use a remote MCP server
54
63
  instead if the service offers one (common for docs and knowledge bases:
@@ -99,15 +108,21 @@ in parentheses are the recommendation when the user has no preference.
99
108
  connection lives (`references/set-up-an-integration.md` § 2): each team
100
109
  connects its own, and it is `required` (the agent waits at "needs setup"
101
110
  until the team connects it) or `optional` (its tools appear once
102
- connected). One connection shared by every team is not available yet;
103
- say so if they ask for it. Then offer to set up any that are not ready.
111
+ connected). Or, for integrations that support it, the Source connects it
112
+ once for every team (`owner: "source"`): each team's agent then works only
113
+ inside what is routed to that team (`references/set-up-an-integration.md`
114
+ § 5). Then offer to set up any that are not ready.
104
115
  6. **What teams may add** — their own MCP servers, their own skills, more of
105
116
  their own integrations, or narrowing (removing tools, more approvals). All
106
117
  off unless there is a reason. Give one concrete example per knob.
107
118
  7. **What starts it** — see `references/triggers.md`. Declare the triggers in
108
119
  the template (an event such as `zendesk.ticket_created` with its filters,
109
120
  a schedule, a webhook) so every team gets them, or leave them to each
110
- team. Say what each team needs connected first.
121
+ team. Take event ids from the catalog's `agentEvents`, which lists every
122
+ event a product declares (Linear also has `linear.issue_labeled`,
123
+ `linear.issue_created` and `linear.assigned`; Zendesk also has
124
+ `zendesk.comment_added`) — map an old trigger onto the matching event
125
+ rather than onto an @mention. Say what each team needs connected first.
111
126
  8. **Who it works with** — other agents of this Source it may ask or hand
112
127
  work to (`links`). A link only exists in a team that runs both agents.
113
128
  9. **What teams may change** — `teamOverrides` per area (approvals,
@@ -39,7 +39,7 @@ conflicting change unless `--overwrite`. Unknown fields are refused.
39
39
  "key": "new-tickets",
40
40
  "type": "event",
41
41
  "event": "zendesk.ticket_created",
42
- "filter": { "tags": ["vip", "urgent"], "brand": "123", "reply_as": "internal_note" }
42
+ "filter": { "tags": ["vip", "urgent"], "brands": ["Acme Support"] }
43
43
  },
44
44
  {
45
45
  "key": "weekday-digest",
@@ -70,6 +70,13 @@ The tool names above are illustrations. Take real ones from
70
70
  - `all`: every tool, reads and changes.
71
71
  - `custom`: whole `products` (slugs) plus single `tools` (names).
72
72
  A tool it must never call is simply not granted — there is no deny list.
73
+ **Knowledge** (Ekanos's own knowledge base, `ekanos knowledge`): add
74
+ `search_knowledge` and `read_knowledge_article` to `tools.tools` for an
75
+ agent that should look things up — they read the team's collection plus
76
+ the Source's General collection, and the agent never picks which. A
77
+ feedback agent that turns reviewer corrections into articles also gets
78
+ `propose_knowledge_article` (a write: it waits for approval by default).
79
+ These are named one by one; no mode or product grants them.
73
80
  Extra team integrations (`teamCustomization.integrations`) need `custom`.
74
81
  - **`policy`** — for each granted tool, `auto` (runs on its own) or
75
82
  `approve` (waits for a person in the app). `reads`/`writes` set the
@@ -80,8 +87,13 @@ The tool names above are illustrations. Take real ones from
80
87
  folders in `agents/<key>/skills/<slug>/` are pushed and added here by
81
88
  `agents apply` (see `skills.md`).
82
89
  - **`connections`** — by product slug: `{ "owner": "team", "team": "required" | "optional" }`.
83
- A product with no entry is `team`/`optional`. `owner: "source"` (one
84
- connection for every team) is refused today.
90
+ A product with no entry is `team`/`optional`. `{ "owner": "source" }` is
91
+ one connection the Source admin makes for every team (`ekanos apps
92
+ connect`), used only by this provided agent and limited per team by the
93
+ Source's routing (`ekanos routes`); `apply` refuses it for an integration
94
+ that does not declare `sourceConnection`. Teams cannot add a Source-owned
95
+ product in their overlay. `mcpServers` with `owner: "source"` are still
96
+ refused.
85
97
  - **`mcpServers`** — remote MCP servers (streamable HTTP, `https` only, up to
86
98
  10): `key` (lowercase, ≤31), `name`, `url`, `auth` (`none` | `bearer` |
87
99
  `oauth`, default `oauth`), `owner`/`team` as for connections, and
@@ -103,9 +115,14 @@ The tool names above are illustrations. Take real ones from
103
115
  an optional `prompt` (what to do each time), and `enabled` (default
104
116
  `true`; `false` sets it up turned off). Types:
105
117
  - `event` — `event` is an integration event (`<slug>.<event>`, as
106
- `ekanos catalog <product>` lists under `agentEvents`); `filter` holds the
107
- event's declared filter fields (Zendesk: `organization`, `brand`,
108
- `group`, `tags`, `reply_as` …).
118
+ `ekanos catalog <product> --json` lists under `agentEvents` — every
119
+ event the product declares, e.g. Zendesk `zendesk.ticket_created` and
120
+ `zendesk.comment_added`, Linear `linear.mentioned`, `linear.assigned`,
121
+ `linear.issue_labeled` and `linear.issue_created`); `filter` holds only
122
+ the keys in that event's `filterFields` (Zendesk: `brands`, `groups`,
123
+ `tags`, `organizations`, each a list; Linear: `teamKeys`, plus `labels`,
124
+ which `linear.issue_labeled` requires). Zendesk's `reply_as` is not a
125
+ filter: it is set in the Zendesk trigger's body (`triggers.md`).
109
126
  - `schedule` — `cron` (5 fields, on a 5-minute boundary) and `timezone`
110
127
  (IANA, default `UTC`); give it a `prompt`.
111
128
  - `webhook` — each team gets its **own** URL and secret, created or
@@ -138,7 +155,9 @@ ekanos agents policy <key> unset zendesk_add_comment
138
155
  ekanos agents policy <key> --reads auto --writes approve
139
156
  ekanos agents triggers <key> # list
140
157
  ekanos agents triggers <key> add event new-tickets --event zendesk.ticket_created \
141
- --filter tags=vip,urgent --filter brand=123 --filter reply_as=internal_note
158
+ --filter tags=vip,urgent --filter brands=Acme,
159
+ ekanos agents triggers <key> add event feedback-label --event linear.issue_labeled \
160
+ --filter labels=feedback,
142
161
  ekanos agents triggers <key> add schedule weekday-digest --cron "0 9 * * 1-5" \
143
162
  --timezone America/Los_Angeles --prompt "Summarize yesterday's escalations."
144
163
  ekanos agents triggers <key> add webhook inbound --prompt "Triage the posted ticket."
@@ -151,7 +170,9 @@ ekanos agents overrides <key> disable policy
151
170
  ```
152
171
 
153
172
  `--filter field=value` repeats; a value with commas is a list, `true` or
154
- `false` a switch, anything else text. `--disabled` adds a trigger turned off.
173
+ `false` a switch, anything else text. A list field (`tags`, `brands`,
174
+ `labels`, `teamKeys` …) needs a list even for one item, so end a single
175
+ item with a comma: `--filter labels=feedback,`. `--disabled` adds a trigger turned off.
155
176
 
156
177
  ## What the host checks on `apply`
157
178
 
@@ -47,7 +47,8 @@ working from those rather than from Ekanos.
47
47
  npx @ekanos/cli apps set <product> --source <slug>
48
48
  ```
49
49
 
50
- It asks for the client ID, then the secret with hidden input. For a team's
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
51
52
  app, they enter the fields in the team's setup panel in the Ekanos app.
52
53
  - Then check: `apps show <product> --source <slug> --json` should say
53
54
  `configured: true`, and the catalog's step should be `done`. Tell them
@@ -35,12 +35,14 @@ integration: its members, its data and its connections.
35
35
  |---|---|---|---|
36
36
  | **Each team, through the Source's app** | One app, created once for the whole Source under the Source's own name. Each team then signs in through it. | The Source admin creates the app (`references/app-setup.md`, `ekanos apps set`); each team connects | Linear, Slack: products where every team is a separate workspace |
37
37
  | **Each team, with its own app** | Each team creates its own app in the provider and enters its credentials | Each team, or the Source admin on the team's behalf with `ekanos teams` (below) | Zendesk: each bank or business has its own Zendesk |
38
- | **One connection for the whole Source** | Every team's provided agent uses the Source's single connection, limited to what is routed to that team | The Source admin, once | One shared Zendesk for many teams. **Not available yet**: say so, and suggest a connection per team for now |
38
+ | **One connection for the whole Source** | Every team's provided agent uses the Source's single connection, limited to the records routed to that team (for Zendesk, the tickets of the organizations mapped to it) | The Source admin, once, plus a routing table | One shared Zendesk for many teams (§ 5). Only for integrations that declare it (Zendesk from 0.2.0; `agents apply` refuses the others), and only for **provided agents**: a team's own agents, widgets and assistant never use it |
39
39
 
40
40
  The agent records the choice in `agent.json` → `connections`:
41
41
  `{ "zendesk": { "owner": "team", "team": "required" } }` means each team
42
42
  uses its own Zendesk and the agent waits at "needs setup" until it is
43
- connected (`references/agent-json.md`).
43
+ connected (`references/agent-json.md`). `{ "zendesk": { "owner": "source" } }`
44
+ means every team's copy of the agent uses the Source's one Zendesk; teams
45
+ connect nothing for it.
44
46
 
45
47
  ## 3. Walk it, one step per message
46
48
 
@@ -60,11 +62,16 @@ connected (`references/agent-json.md`).
60
62
  `ekanos teams app set`, with hidden input) or in the team's page in the app.
61
63
  If they paste one into the chat anyway, tell them to rotate it in the
62
64
  provider's console and enter the new one at the terminal.
63
- - **Signing in is a person's click.** Connecting (the provider's consent
64
- screen) happens in the browser, by someone on the team, from the link in
65
- `teams show` (or just the link and whether it is connected yet:
66
- `teams connect <team> <product>`). Tell them who should click it: the account the integration
67
- acts as. A dedicated seat such as "Support agent" makes its replies easy
65
+ - **Connect with `teams connect <team> <product>`, run by the user in their
66
+ own terminal.** It does whatever the integration needs: asks a form's fields
67
+ (secrets hidden), runs the team-app prompts first when the team's own app is
68
+ missing, or opens a one-time sign-in link and waits until the team is
69
+ connected. The provider's consent is still a person's click, by a member of
70
+ the team (owner/admin for a team-wide connection): the user when they are
71
+ one, else `--as <email>` prints a link to send that member. `--link-only`
72
+ prints just the team's page. Tell them who should sign in: the account the
73
+ integration acts as. If the product is not enabled for the Source, a
74
+ super-admin enables it (`sources products` shows what the Source has). A dedicated seat such as "Support agent" makes its replies easy
68
75
  to recognise.
69
76
  - **Close each product out**: one line on what now works ("New tickets in
70
77
  Acme's Zendesk will start the support agent"), then move on to the next
@@ -80,8 +87,13 @@ pilot), the team-side steps can be done from the CLI:
80
87
  2. They create the app in the provider's console, step by step as above.
81
88
  3. **In their own terminal:**
82
89
  `npx @ekanos/cli teams app set <team> <product> --source <slug>`. It asks
83
- for each field and hides the secret ones. It refuses to run inside Claude;
84
- that is deliberate.
90
+ for each field and hides the secret ones; Enter keeps a saved value. It
91
+ refuses to run inside Claude; that is deliberate. To change one value
92
+ later, they need not re-enter the rest:
93
+ `teams app set <team> <product> --field <name>` asks for just that field
94
+ (names are in brackets in `teams show`), `--set <name>=<value>` sets a
95
+ non-secret field (a subdomain, a client ID) without a prompt — you may run
96
+ that one yourself — and `--clear <name>` removes a value.
85
97
  4. If the integration takes webhooks:
86
98
  `npx @ekanos/cli teams webhook <team> <product> --source <slug>` prints the
87
99
  team's webhook URL **once**. Have them paste it into the provider at that
@@ -90,6 +102,59 @@ pilot), the team-side steps can be done from the CLI:
90
102
  5. Someone on the team opens the link from `teams show` and clicks Connect.
91
103
  6. `teams show` again: every step ✓.
92
104
 
105
+ ## 5. One connection for the whole Source
106
+
107
+ Use it when one account at the provider serves many teams: one Zendesk where
108
+ each bank is an organization. The Source admin connects once; events are
109
+ routed to teams by a value inside them (for Zendesk, the ticket's
110
+ **organization**); each team's provided agent then works only inside what is
111
+ routed to that team. Say all three parts before starting, and say plainly
112
+ what it does **not** do: a team's own agents, widgets and assistant never see
113
+ the Source's connection.
114
+
115
+ 1. **Connect, once, as the Source.** For an integration where each customer
116
+ brings its own app (Zendesk), first create that app in the shared account,
117
+ exactly as in the worked example below (OAuth client, Confidential), but
118
+ once, for the Source. Then, **in their own terminal**:
119
+ `npx @ekanos/cli apps connect <product> --source <slug>`. It asks for the
120
+ app's fields it doesn't have yet (Zendesk: subdomain, client ID, client
121
+ secret, webhook signing secret; secrets hidden, never as flags, and it
122
+ refuses to run inside Claude), prints the redirect URL to register and the
123
+ consent link, then waits up to ten minutes until it is connected. Whoever
124
+ clicks the link is the account the integration acts as for every team, so
125
+ suggest a dedicated seat ("Support agent"). `apps list` shows every
126
+ integration the Source can connect this way. Check with
127
+ `npx @ekanos/cli apps show <product> --source <slug>`: connected, by whom,
128
+ when. In the app the same lives in the Source admin area under
129
+ **Shared integrations › Connections**.
130
+ 2. **The Source's webhook.** `npx @ekanos/cli routes webhook <product> --source <slug>`
131
+ prints one URL, **once**, for the whole Source. Paste it into the
132
+ provider at that moment (for Zendesk, the webhook the triggers notify).
133
+ The team webhooks from § 4 are not used for this connection.
134
+ 3. **Map values to teams.** `npx @ekanos/cli routes options <product> --source <slug>`
135
+ lists what can be mapped (Zendesk organizations, with names), then one
136
+ line per team:
137
+ `npx @ekanos/cli routes set <product> <value> <team> --source <slug>`.
138
+ `routes list` shows the table. One value goes to exactly one team.
139
+ 4. **The agent.** In `agent.json`, `connections.<product>` is
140
+ `{ "owner": "source" }`; `agents apply` accepts it only when the
141
+ integration supports a Source connection. Teams turn the agent on as
142
+ usual; they connect nothing for that product.
143
+ 5. **Try it.** A ticket from a mapped organization starts that team's agent
144
+ only. A ticket from an organization nobody mapped starts **nothing**: the
145
+ integration leaves its own fixed note (Zendesk: an internal note saying
146
+ no team has it yet), and it is listed by
147
+ `npx @ekanos/cli routes unrouted <product> --source <slug>`. Map the
148
+ value, then `routes replay <event-id>` to send it on once.
149
+
150
+ What is enforced, so you can say it accurately: the host routes each event
151
+ to exactly one team or to none (never to a default team), and gives a
152
+ team's agent only that team's mapped values (`ctx.routing`); the
153
+ integration's tools keep to them (for Zendesk, reads are limited to the
154
+ team's organizations, and anything that reads or changes one ticket first
155
+ checks its organization and refuses otherwise). The agent's policy,
156
+ approvals and audit apply exactly as on a team connection.
157
+
93
158
  ## Worked example: Zendesk for one team
94
159
 
95
160
  The steps below are what Zendesk's own setup says, in order. Take the URLs
@@ -104,7 +169,8 @@ from `teams show zendesk`.
104
169
  secret.
105
170
  3. **Credentials into Ekanos.** `ekanos teams app set <team> zendesk` in
106
171
  their terminal: subdomain, client ID, client secret, webhook signing
107
- secret.
172
+ secret. Any of them can be entered or changed later on its own
173
+ (`--field <name>`); `teams show` says which are saved.
108
174
  4. **Connect.** Someone on the team opens the link and connects, as the
109
175
  Zendesk agent the integration should reply as.
110
176
  5. **Zendesk triggers.** Objects and rules › Triggers: one for *Ticket is
@@ -70,9 +70,12 @@ whose `teamCustomization.skills` is on.
70
70
 
71
71
  ## Limits today
72
72
 
73
- - Prompt skills only: the agent reads `SKILL.md`'s instructions. Files under
74
- `references/` and `assets/` are stored with each version and come back with
75
- `pull`, but the agent does not open them at run time — put what it must
76
- know in `SKILL.md`.
73
+ - Prompt skills only. At run time the agent gets the whole folder: loading
74
+ the skill returns `SKILL.md`'s instructions plus the list of every other
75
+ file (`references/`, `assets/`, …), and it reads one on demand
76
+ (`read_skill_file`) when the instructions point to it — so keep `SKILL.md`
77
+ short and name the reference to open, e.g. `references/policy-2026.md`.
78
+ Text files are read in parts of about 12,000 characters; binary files are
79
+ listed but cannot be read as text.
77
80
  - A `scripts/` folder is refused: executable skills need the in-app review.
78
81
  - Up to 100 files, 1 MB per file, 3 MB per skill.
@@ -20,7 +20,14 @@ A Source admin can add them for the team from the terminal instead:
20
20
  `ekanos teams triggers add acme-support support-agent event zendesk.ticket_created --filter '{"tags":["billing"]}'`,
21
21
  `… schedule --cron "0 9 * * 1-5" --timezone America/Los_Angeles --prompt "…"`,
22
22
  `… webhook --prompt "…"` (prints the URL and token once) or `… manual`.
23
- Slack and Linear triggers are added in the app. When a provided agent's
23
+ Any event in a connected integration's `agentEvents` is added this way,
24
+ 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
28
+ the Linear integration, and its limits are not the integration's: an agent
29
+ that should start when a label is applied uses `linear.issue_labeled`, not an
30
+ @mention. When a provided agent's
24
31
  template declares triggers and has not turned on team overrides for them, the
25
32
  team's triggers follow the template and these commands refuse to change them.
26
33
 
@@ -39,23 +46,45 @@ team's triggers follow the template and these commands refuse to change them.
39
46
 
40
47
  ## Integrations with agent events
41
48
 
42
- Check `ekanos catalog <product> --source <slug> --json` for what is actually
43
- there; these are the known shapes.
49
+ `ekanos catalog <product> --source <slug> --json` is the authority: its
50
+ `agentEvents` lists **every** event the product declares, with each one's
51
+ filter keys (`filterFields`). The lists below are the known shapes; never
52
+ conclude a product lacks an event because an example here or elsewhere
53
+ names only one. A refused event id is answered with the ids the product
54
+ does declare, and a refused filter with the keys the event takes.
44
55
 
45
- **Linear** (`linear.mentioned`, `linear.assigned`, `linear.issue_labeled`) —
46
- the agent becomes a teammate in Linear: @mention it, assign it an issue, or
47
- apply a label. Each team needs two things in the app: each person's own
48
- Linear connection (for the tools), and the team's own Linear app for the
49
- agent (client id, secret and webhook signing secret, entered in Ekanos).
56
+ An event can be declared and still never fire for a team until the team
57
+ finishes that event's own setup on the provider's side. That is a setup
58
+ step, not a missing event — say which step, as below.
59
+
60
+ **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).
50
64
  Guide: https://sdk.ekanos.dev/guides/linear-agent
51
65
 
52
- **Zendesk** (`zendesk.ticket_created`, `zendesk.comment_added`; filters such
53
- as brand, group, tags, organization) — when present in the catalog, each team
54
- connects its own Zendesk (subdomain plus an OAuth client it creates in
55
- Zendesk) and adds a Zendesk webhook pointing at its Ekanos endpoint
56
- (walk-through: `set-up-an-integration.md`, worked example). The agent
57
- answers on the ticket as a public reply or an internal note — recommend
58
- internal notes, or approval on public replies, until the team trusts it.
66
+ | Event | Starts when | Filter keys | Needs on the team's Linear app |
67
+ |---|---|---|---|
68
+ | `linear.mentioned` | someone @mentions the agent, or writes to it again in that conversation | `teamKeys` | webhook with **Agent session events** ticked |
69
+ | `linear.assigned` | someone assigns (delegates) an issue to the agent | `teamKeys` | webhook with **Agent session events** ticked |
70
+ | `linear.issue_labeled` | someone applies one of the given labels to an issue | `labels` (**required**), `teamKeys` | webhook with **Issues** ticked |
71
+ | `linear.issue_created` | someone creates an issue (optionally only with given labels) | `labels`, `teamKeys` | webhook with **Issues** ticked |
72
+
73
+ **Zendesk** — each team connects its own Zendesk (subdomain plus an OAuth
74
+ client it creates in Zendesk) and adds a Zendesk webhook pointing at its
75
+ Ekanos endpoint (walk-through: `set-up-an-integration.md`, worked example).
76
+ The agent answers on the ticket as a public reply or an internal note —
77
+ recommend internal notes, or approval on public replies, until the team
78
+ trusts it.
79
+
80
+ | Event | Starts when | Filter keys | Needs in Zendesk |
81
+ |---|---|---|---|
82
+ | `zendesk.ticket_created` | a new ticket arrives | `brands`, `groups`, `tags`, `organizations` | a Zendesk trigger on *Ticket is Created* notifying the webhook |
83
+ | `zendesk.comment_added` | an end user (requester or CC) comments on a ticket; agent and admin comments never start it | `brands`, `groups`, `tags`, `organizations` | a **second** Zendesk trigger, on a customer's public reply, notifying the webhook |
84
+
85
+ Filter values are lists (`{"tags":["billing"],"brands":["Acme Support"]}`);
86
+ brands, groups and organizations match by name or id. Where the answer goes
87
+ (`reply_as`) is set in the Zendesk trigger's body, not in the filter.
59
88
 
60
89
  ## Checklist to hand each team
61
90
 
@@ -53,7 +53,9 @@ npx @ekanos/cli teams members invite bank-a raj@bank-a.com --role admin # defa
53
53
  npx @ekanos/cli teams members list bank-a # members and pending invitations
54
54
  npx @ekanos/cli teams members role bank-a raj@bank-a.com member
55
55
  npx @ekanos/cli teams members remove bank-a raj@bank-a.com --yes
56
- npx @ekanos/cli teams connect bank-a zendesk # the link a member opens to connect
56
+ npx @ekanos/cli teams connect bank-a zendesk # connect it for the team (asks, signs in, waits)
57
+ npx @ekanos/cli teams connect bank-a linear --as raj@bank-a.com # a sign-in link for raj
58
+ npx @ekanos/cli sources products # what the Source has enabled (super-admin enables)
57
59
  ```
58
60
 
59
61
  - `create` without `--owner` seats the person running it as the team's
@@ -66,9 +68,18 @@ npx @ekanos/cli teams connect bank-a zendesk # the link a membe
66
68
  customized ones). Pick a reviewer for agents by the role holding
67
69
  `agents.review` in `teams roles list`. The primary owner's role cannot be
68
70
  changed here; ownership moves in the app.
69
- - Connecting an integration is always a team member signing in in their
70
- browser. `teams connect` prints the link to send them and whether the team
71
- is connected yet; `teams show <team> <product>` has the full checklist.
71
+ - `teams connect <team> <product>` does the connect: it asks a form's fields
72
+ at the user's terminal (hidden for secrets — so the user runs it, never you
73
+ with values), runs the team-app prompts first when needed (Zendesk), or
74
+ opens a one-time sign-in link and waits. The person who signs in is a team
75
+ member (owner/admin for a team-wide connection): the user when they are
76
+ one, else `--as <email>` prints a link to send that member. `--no-wait`,
77
+ `--no-open`, `--link-only` (just the team's page). `teams show <team>
78
+ <product>` has the full checklist.
79
+ - A product the Source does not have is refused; `sources products` lists
80
+ what it has. Enabling one is a super-admin grant (`sources products enable`)
81
+ that an `ekanos login` session cannot make — the super-admin does it in
82
+ /admin.
72
83
 
73
84
  ## Products: integrations and experiences
74
85
 
@@ -77,7 +88,11 @@ Everything in the catalog (`npx @ekanos/cli catalog --source <slug> --json`) is
77
88
 
78
89
  - **Integration** — a connection to a third party (Linear, Zendesk, Slack…).
79
90
  Brings tools an agent can call, and may declare **agent events** that start
80
- agents (`linear.mentioned`, `zendesk.ticket_created`…).
91
+ agents — Linear declares `linear.mentioned`, `linear.assigned`,
92
+ `linear.issue_labeled` and `linear.issue_created`; Zendesk declares
93
+ `zendesk.ticket_created` and `zendesk.comment_added`. The catalog's
94
+ `agentEvents` is the authority: read it before concluding a product lacks
95
+ an event, never infer the set from an example.
81
96
  - **Experience** — an Ekanos-native capability (Agents, Workflows, Home…).
82
97
  Never "connected"; it is simply on or off for the Source.
83
98
 
@@ -97,8 +112,12 @@ Ask them in this order; each catalog product reports where it stands
97
112
  connection: two teams using Linear each connect their own. A Source admin
98
113
  can do a team's setup for it from the terminal (`ekanos teams show`,
99
114
  `ekanos teams app set`, `ekanos teams webhook`), but signing in is a click
100
- by someone on the team. One connection for the whole Source, shared by
101
- every team's agents, is not available yet.
115
+ by someone on the team. For integrations that support it, a Source admin
116
+ can instead connect **once for the whole Source** (`ekanos apps connect`),
117
+ for provided agents only: events are routed to teams by a value inside
118
+ them (`ekanos routes`, Zendesk by organization), and each team's agent
119
+ works only inside its own routed values. A team never sees that
120
+ connection.
102
121
  3. **Set up by the team** where needed — some integrations have each team
103
122
  bring its own app (a team-provided app: client id, secret, webhook signing
104
123
  secret entered in Ekanos). Those secrets are typed into the app, never
@@ -140,6 +159,14 @@ Skills are folders (`SKILL.md` + references) an agent loads when needed.
140
159
  A Source admin pushes them with `ekanos skills push <dir>`: at Source level
141
160
  every team can use them, with `--team <slug>` only that team can.
142
161
 
162
+ **Knowledge** is Ekanos's own knowledge base (no outside account): markdown
163
+ 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` /
167
+ `read_knowledge_article` search their own team's collection and General.
168
+ Skills say *how* to work; Knowledge holds the facts an agent looks up.
169
+
143
170
  The `build-agent` skill walks through choosing between these and building one.
144
171
 
145
172
  A Source admin can also do a team's agent setup from the terminal, acting on
@@ -161,7 +188,9 @@ always `ekanos teams <area> <verb> <team> …`:
161
188
  follows its template unless the template turns on team overrides for it.
162
189
  - `ekanos teams triggers list|add|remove <team> <key> …` — manual, schedule
163
190
  (`--cron`, `--timezone`), webhook (URL and token shown once) and
164
- integration events (`event zendesk.ticket_created --filter '{…}'`).
191
+ integration events (`event zendesk.ticket_created --filter '{…}'`, or any
192
+ other id in the product's `agentEvents`, e.g. `event linear.issue_labeled
193
+ --filter '{"labels":["feedback"]}'`).
165
194
  - `ekanos teams links list|add|remove <team> <from-key> [<to-key>] --kind
166
195
  talk|delegate [--mode await|handoff]`.
167
196
  - `ekanos teams mcp list|add|status|token|effect <team> [<server-key> …]` — a
@@ -211,8 +240,11 @@ is refused (`USER_NOT_IN_SOURCE`): `ekanos teams list` shows the teams.
211
240
  | 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` |
212
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` |
213
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) |
243
+ | 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 |
214
244
  | Who decides agent drafts that wait for a person | A Source admin, with `ekanos reviewers` |
215
245
  | An integration's app for the whole Source (client ID and secret) | A Source admin, with `ekanos apps set` at their own terminal |
246
+ | 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 |
247
+ | 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 |
216
248
  | 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` |
217
249
  | 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 |
218
250
  | 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) |