eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1# πŸ€– The integrations registry
2
3One JSON manifest per third-party service. A manifest is the WHOLE of what an
4integration can do on an Eleven Messenger instance: how a member authenticates
5to the service, the one API host its operations may touch, and the closed list
6of operations β€” each marked `read` or `write`, writes each carrying the
7confirmation line a person taps before it runs. An operation that isn't in the
8manifest cannot be expressed, the same fail-closed palette rule as bot recipes
9(`docs/bot-recipes.md`).
10
11This directory is destined to become its own public repository
12(`elevenmessenger/integrations`) so integrations can be added β€” and audited β€”
13without touching the messenger codebase: adding one is a PR with a manifest
14(plus, for OAuth services, registering the OAuth app on the connect broker,
15which is where client secrets live β€” `docs/connected-services.md`). Until that
16split, it lives here and is embedded into the binaries (`registry.go`), with
17the broker serving it at `GET /registry` so web clients read the same catalog.
18
19## Manifest schema (v1)
20
21```jsonc
22{
23 "schema": 1,
24 "id": "github", // lowercase slug, unique
25 "name": "GitHub",
26 "category": "development", // catalog grouping
27 "auth": {
28 "kind": "pat", // "pat" | "oauth" | "both"
29 "base": "https://api.github.com",// the ONLY host ops may reach (executor-pinned)
30 "authorization": "Bearer", // Authorization: <scheme> <token>; "none" sends the bare token (Linear)
31 "headers": { "Accept": "…" }, // extra headers on every call
32 "pat_help": "…", // where a member mints a scoped token
33 "oauth": { "authorize_url": "…", "scopes": ["…"] } // when the broker has an app
34 },
35 "ops": [
36 {
37 "id": "repos.list", // namespace.verb, unique within the manifest
38 "label": "List your repositories",
39 "access": "read", // "read" | "write" β€” grants are scoped to this
40 "method": "GET",
41 "path": "/user/repos?per_page=20", // {arg} placeholders allowed
42 "args": { "owner": { "required": true } }, // string args only; validated
43 "body_json": { "title": "{title}" }, // JSON body template ({arg} in leaves)
44 "encoding": "json", // "json" (default) | "form" (Stripe-style)
45 "confirm": "Open β€œ{title}”?", // REQUIRED on writes: the consent chip's line
46 "pick": { // response projection β€” what may flow BACK
47 "root": "data", // descend into an envelope first (optional)
48 "fields": ["full_name", "user.login"] // keep only these dot-paths per object
49 }
50 }
51 ]
52}
53```
54
55`pick` makes the response as reviewable as the request: provider APIs answer
56with far more than an app needs (a GitHub repo object is ~100 fields, several
57KB), and an op result travels inside one end-to-end-encrypted message with a
58hard size cap β€” so the manifest declares the fields that may flow back, and the
59executor drops everything else before the result ever leaves the sidecar.
60Applied to the object at `root` (or to each object of the array there); nested
61paths come back flattened (`"user.login": "octocat"`). An op without `pick`
62returns the raw body, still subject to the size cap.
63
64Rules the loader enforces (fail closed β€” a bad manifest never half-loads):
65
66- `id`/op ids well-formed; op ids unique; `access` ∈ read/write; every write
67 has a `confirm` template; `base` is https; methods ∈ GET/POST/PUT/PATCH/DELETE.
68- `{arg}` placeholders in `path`/`body_json`/`confirm` must name declared args.
69- Arg values are strings, bounded, and escaped into the URL β€” a value can
70 never break out of its path segment or query slot.
71- `pick` (when present) names at least a root or one field, all well-formed
72 dot-paths.
73
74## Trust model
75
76The manifest is reviewed CODE (this registry), never user content. The
77executor pins every request to `auth.base`'s host, so a manifest op can't be
78steered elsewhere. Member credentials stay client-sealed exactly as before
79(`docs/connected-services.md`): a bot receives a short-lived grant sealed to
80its own key, now carrying `access: "read" | "write"` β€” a read grant cannot run
81a write op, and grants are per-bot by construction (sealed to one keypair).
82Writes additionally require the member's tap on a confirmation chip naming the
83exact operation ("Register blip.com β€” this costs real money").
84