@zackbart/connecta 0.33.0 → 0.34.1

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 (131) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +100 -128
  3. package/SECURITY.md +1 -1
  4. package/bin/version.mjs +1 -1
  5. package/dist/activity.d.ts +3 -0
  6. package/dist/branding.d.ts +7 -0
  7. package/dist/branding.js +76 -9
  8. package/dist/catalog-drift.d.ts +30 -26
  9. package/dist/catalog-drift.js +169 -84
  10. package/dist/catalog-service.js +16 -2
  11. package/dist/config-value-sources.js +6 -1
  12. package/dist/config.d.ts +13 -2
  13. package/dist/config.js +36 -2
  14. package/dist/connector-caller.js +2 -1
  15. package/dist/connectors/api-connector.d.ts +3 -0
  16. package/dist/connectors/api-connector.js +5 -1
  17. package/dist/connectors/option-shapes.js +1 -1
  18. package/dist/connectors/remote-mcp.d.ts +2 -0
  19. package/dist/connectors/remote-mcp.js +5 -1
  20. package/dist/describe-config.d.ts +5 -1
  21. package/dist/describe-config.js +2 -0
  22. package/dist/execute.js +1 -11
  23. package/dist/fix-prompt.js +2 -2
  24. package/dist/index.js +1 -0
  25. package/dist/invocation.js +3 -2
  26. package/dist/membership.d.ts +2 -0
  27. package/dist/meta-tools.js +3 -2
  28. package/dist/oauth-callback-outcome.js +2 -2
  29. package/dist/operator-ui/agents.d.ts +1 -1
  30. package/dist/operator-ui/agents.js +16 -16
  31. package/dist/operator-ui/config-summary.js +565 -0
  32. package/dist/operator-ui/connection-map.js +376 -0
  33. package/dist/operator-ui/endpoints.js +45 -16
  34. package/dist/operator-ui/fix-prompts.js +1 -1
  35. package/dist/operator-ui/generated.js +4 -4
  36. package/dist/operator-ui/health.js +52 -0
  37. package/dist/operator-ui/member-page.js +13 -28
  38. package/dist/operator-ui/overview.js +123 -0
  39. package/dist/operator-ui/view.d.ts +26 -22
  40. package/dist/operator-ui/view.js +130 -96
  41. package/dist/page-styles.js +5 -3
  42. package/dist/provider.d.ts +6 -1
  43. package/dist/provider.js +18 -1
  44. package/dist/providers/_shared/google/workspace.d.ts +9 -4
  45. package/dist/providers/_shared/google/workspace.js +7 -3
  46. package/dist/providers/basecamp/index.d.ts +2 -0
  47. package/dist/providers/breeze/index.d.ts +2 -0
  48. package/dist/providers/ccb/index.d.ts +2 -0
  49. package/dist/providers/ccb/index.js +2 -2
  50. package/dist/providers/cloudflare/index.d.ts +2 -0
  51. package/dist/providers/cloudflare/index.js +5 -1
  52. package/dist/providers/cloudflare/openapi.generated.js +3296 -3206
  53. package/dist/providers/cloudflare/rest.js +19 -0
  54. package/dist/providers/cloudflare/skill.generated.js +2 -2
  55. package/dist/providers/cloudflare/value-safety.js +51 -18
  56. package/dist/providers/docs/index.js +1 -1
  57. package/dist/providers/docs/skill.generated.js +2 -2
  58. package/dist/providers/drive/index.js +1 -1
  59. package/dist/providers/drive/skill.generated.js +2 -2
  60. package/dist/providers/forms/index.js +1 -1
  61. package/dist/providers/forms/skill.generated.js +2 -2
  62. package/dist/providers/gmail/index.js +1 -1
  63. package/dist/providers/gmail/skill.generated.js +2 -2
  64. package/dist/providers/intercom/index.d.ts +24 -0
  65. package/dist/providers/intercom/index.js +121 -0
  66. package/dist/providers/intercom/skill.generated.js +8 -0
  67. package/dist/providers/linear/index.js +204 -19
  68. package/dist/providers/linear/skill.generated.js +2 -2
  69. package/dist/providers/mixpanel/index.d.ts +2 -0
  70. package/dist/providers/mixpanel/index.js +21 -17
  71. package/dist/providers/mixpanel/skill.generated.js +3 -3
  72. package/dist/providers/notion/index.d.ts +2 -0
  73. package/dist/providers/notion/index.js +1 -1
  74. package/dist/providers/notion/skill.generated.js +1 -1
  75. package/dist/providers/overflow/index.d.ts +2 -0
  76. package/dist/providers/overflow/index.js +1 -1
  77. package/dist/providers/overflow/skill.generated.js +2 -2
  78. package/dist/providers/planning-center/index.d.ts +2 -0
  79. package/dist/providers/planning-center/index.js +1 -1
  80. package/dist/providers/planning-center/skill.generated.js +4 -4
  81. package/dist/providers/revenuecat/index.d.ts +5 -3
  82. package/dist/providers/revenuecat/index.js +147 -7
  83. package/dist/providers/revenuecat/skill.generated.js +3 -3
  84. package/dist/providers/sheets/index.js +1 -1
  85. package/dist/providers/sheets/skill.generated.js +2 -2
  86. package/dist/providers/slides/index.js +1 -1
  87. package/dist/providers/slides/skill.generated.js +2 -2
  88. package/dist/providers/stripe/index.d.ts +2 -0
  89. package/dist/providers/stripe/index.js +50 -30
  90. package/dist/providers/stripe/skill.generated.js +2 -1
  91. package/dist/providers/tithely/index.d.ts +2 -0
  92. package/dist/providers/tithely/index.js +1 -1
  93. package/dist/providers/vercel/index.d.ts +2 -0
  94. package/dist/providers/vercel/index.js +2 -2
  95. package/dist/providers/vercel/openapi.generated.js +391 -374
  96. package/dist/providers/vercel/skill.generated.js +2 -2
  97. package/dist/providers/vercel/value-safety.js +14 -4
  98. package/dist/registry.d.ts +10 -14
  99. package/dist/registry.js +77 -62
  100. package/dist/routes/mcp.js +20 -13
  101. package/dist/routes/oauth.js +2 -2
  102. package/dist/routes/ui-data.js +8 -2
  103. package/dist/skills.js +18 -2
  104. package/dist/storage/sql.js +5 -1
  105. package/dist/types.d.ts +36 -11
  106. package/dist/ui.js +9 -4
  107. package/dist/usage-guide.js +1 -1
  108. package/dist/version.d.ts +1 -1
  109. package/dist/version.js +1 -1
  110. package/documentation/README.md +2 -2
  111. package/documentation/architecture.md +66 -18
  112. package/documentation/auth.md +183 -67
  113. package/documentation/code-mode.md +30 -10
  114. package/documentation/deploying.md +5 -1
  115. package/documentation/integrating.md +64 -7
  116. package/documentation/meta-tools.md +38 -24
  117. package/documentation/migration-0.33.md +21 -13
  118. package/documentation/migration-0.34.md +67 -0
  119. package/documentation/operating.md +1 -1
  120. package/documentation/operator-tests.md +52 -20
  121. package/documentation/operator-ui.md +341 -104
  122. package/documentation/provider-auth-migration.md +22 -0
  123. package/examples/worker/AGENTS.md +15 -9
  124. package/examples/worker/README.md +41 -14
  125. package/examples/worker/src/connecta.config.ts +5 -4
  126. package/examples/worker/wrangler.jsonc +1 -1
  127. package/package.json +23 -19
  128. package/templates/node/AGENTS.md +13 -7
  129. package/templates/node/README.md +14 -11
  130. package/templates/node/package.json +1 -1
  131. package/templates/node/src/connecta.config.ts +2 -2
@@ -10,6 +10,7 @@ credential ownership, and grants use [Auth](./auth.md).
10
10
  | Task | Read |
11
11
  | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
12
12
  | Enable UI, vault, or history in a deployment | [Setup](#setup), then the platform template |
13
+ | Find what a page shows or where a route goes | [Pages](#pages) |
13
14
  | Find a member's endpoint or set up their client | [Use the member page](#use-the-member-page) |
14
15
  | Consume config, provenance, status, or activity | [Operator data contract](#operator-data-contract) |
15
16
  | Change a UI page or data route | [Source and tests](#source-and-tests), [browser verification](./operator-tests.md) |
@@ -23,82 +24,6 @@ and [Worker example](../examples/worker/README.md#select-optional-modules)
23
24
  own the runnable configuration, variables, and branding shape. The UI is an
24
25
  explicit optional import and stays outside the root package import graph.
25
26
 
26
- Endpoints, Connectors, Activity, Tokens, and Settings are the maintainer's
27
- pages. Endpoints is the default page at `/`: one row for `/mcp` and each pool,
28
- with a copyable URL, who can use it, tool count, endpoint mode, and client
29
- setup. Who can use it is `root.maintainers` on `/mcp` and the pool's `members`
30
- elsewhere: a person by label, or by raw id when the label is null, beside their
31
- initials, and an agent as `agent:<name>` with a token mark. A row shows four
32
- and a "+N more" button that reveals the rest. A pool with
33
- agent members also shows its agent URL, muted. Expanding a row lists each
34
- connector on that endpoint with what it runs as and its tools, marking write
35
- tools. The runs-as label comes from that endpoint's matrix cell. A shared connector
36
- names its credential's source: "Shared · saved <date>" (vault), "Shared ·
37
- connected <date>" (OAuth), "Shared · not configured", "Shared · set in
38
- deployment", or "Shared · no credential needed"; a vault or OAuth cell without a
39
- date omits it. The others read "Personal · N of M connected", "Workspace · people:
40
- self · agents: <owner>" (or "none"), or "Everyone acts as <subject>" for a
41
- fixed-subject Workspace connector. Connector health is not repeated per
42
- endpoint: a connector that needs attention gets a status dot linking to its
43
- Connection tab. Counts intersect live tools with the pool's declared tools
44
- (the `/mcp` matrix cells for the root), guarded grants' live verdicts, and
45
- read-only mode. Connectors lists each connector with one status badge, auth
46
- scope, tool count, and last call; a problem adds one action (Connect, Replace
47
- key, or Inspect) that opens Connection. A List / Matrix toggle (`?view=matrix`)
48
- switches to a table of connectors by endpoint, `/mcp` first: each cell reads
49
- "all", a tool count, or a dash, read-only columns are tinted, and a Runs as
50
- column summarizes the `/mcp` cell, else the first pool's. A cell with tools is
51
- a button named like "GitHub on /mcp/support: 1 tool, read-only"; Enter, Space or
52
- a click opens a popover listing exactly that cell's tool names, write tools
53
- marked, with the cell's runs-as. Escape or Tab returns focus to the cell. The
54
- popover opens below its cell, or above when the viewport has more room there,
55
- with a capped height that scrolls; CSS anchor positioning places it, and the
56
- page sets no inline styles. A browser without anchor positioning gets the same
57
- list, with the same keys, in an expansion row under the connector. `GET /ui/api/config` is the browser's one gate: a 401
58
- shows sign-in, the private 404 shows a "No access" page naming who to ask, with
59
- Sign out or Change token, and a 200 renders by `role`. `/ui/data`, connector
60
- details, activity and tokens are requested only after the contract says
61
- `maintainer`, and every such read checks the role again when it is sent, focus
62
- returns included. Until a role is confirmed, the page shows its loading or
63
- error state and no navigation. The store keeps the last confirmed role through
64
- a failed refresh: a maintainer's page stays mounted, inert and dimmed, under
65
- one shell banner with Retry, whichever page it is, and sends nothing
66
- maintainer-only until a contract confirms the role again. Recovery closes the
67
- page's dialogs, drawers and popovers and the command palette, and moves focus
68
- to Retry. Credential and OAuth writes also wait for a contract that agrees
69
- with the confirmed role: a maintainer's for a connector it shows, a member's
70
- for a personal connector their contract lists with that action in `manage`;
71
- otherwise the write is not sent and its row says so. An
72
- answer with a different role clears everything read under the old one and
73
- admits the viewer again. A
74
- pool member sees the [member page](#use-the-member-page) on every path, with
75
- no tabs. Connector
76
- detail has Tools, Connection, and Activity tabs. Connection combines
77
- authentication (including the OAuth client mechanism), catalog diagnostics,
78
- one fix prompt beside each problem it reports, and the connector snapshot with its source. Settings combines inbound-auth facts with the
79
- configuration snapshot and labels values as default or configured. Deployment code owns connectors, grants, pools, and classification;
80
- the UI changes only authorized authentication material.
81
-
82
- Tokens has one row per agent declared in code, in `GET /ui/access-tokens`
83
- order: its pools, a state badge (No token, Issued or Revoked), the issue or
84
- revoke date, and last seen ("never" when null). One line says agents are
85
- declared in code; nothing creates or renames one. Issue appears for a slot with
86
- no token or a revoked one, Rotate and Revoke for an issued one; rotate and
87
- revoke ask first in a row under the agent's, with focus on Cancel. Every
88
- mutation sends `{ "expect": "<revision>" }` with the slot revision the
89
- operator confirmed against. A new secret opens once in a dialog with a copy
90
- button and a note that it won't be shown again; closing it drops the secret
91
- from the page, and recovery never closes it. A 409 `slot_changed` reads
92
- "Changed since you looked, refresh"; a 503 `outcome_unknown` or 499 `aborted`
93
- is a failure notice and is never retried. Sending a mutation leaves the slot
94
- unresolved until its successful response is validated, which resolves it. Any
95
- other outcome, a contract whose `agents[].token` disagrees with the list
96
- (revision included) or drops the agent, or a failed read leaves it unresolved
97
- until a slot-list read that started afterwards succeeds. Until then its
98
- controls are off with "Refresh to continue", and each action is
99
- checked again immediately before it is sent. Under the recovery banner Tokens
100
- offers no Refresh of its own, and an open rotate or revoke question closes.
101
-
102
27
  Install the vault for declared credential slots and activity history for
103
28
  persisted call records. Neither module grants permission to manage or read
104
29
  it: [auth](./auth.md#management-permissions) does. Interactive maintainers
@@ -108,24 +33,333 @@ Token management issues, rotates, and revokes the tokens of agents declared in
108
33
  code; it never creates, renames, or binds an agent. Agent tokens never grant
109
34
  interactive credential or token management authority.
110
35
 
36
+ ## Pages
37
+
38
+ The UI shows configuration and never edits it. Deployment code owns
39
+ connectors, grants, pools, agents and classification. The UI changes only
40
+ credentials, OAuth connections and agent tokens, through the existing routes.
41
+ No select menu displays configuration. Copy is short labels; a failure names
42
+ what to do next in one or two sentences and never quotes a route's or
43
+ downstream's text.
44
+
45
+ | Path | Page | Who |
46
+ | ------------------ | ------------------------------------------------------ | ---------- |
47
+ | `/` | Overview (a member gets the member page) | Maintainer |
48
+ | `/endpoints` | Endpoints; `#mcp/<pool>` opens that row | Maintainer |
49
+ | `/connectors` | Connectors list; `?view=matrix` for the matrix | Maintainer |
50
+ | `/connectors/<id>` | Connector detail; `#tools`, `#connection`, `#activity` | Maintainer |
51
+ | `/activity` | Activity | Maintainer |
52
+ | `/tokens` | Tokens, when token management is open to the viewer | Maintainer |
53
+ | `/settings` | Settings | Maintainer |
54
+
55
+ `/access` redirects to `/endpoints`, `/tools` to `/connectors`, and `/config`
56
+ to `/settings`, replacing the history entry. Connector hashes `#config`,
57
+ `#auth` and `#diagnostics` redirect to `#connection` and keep query
58
+ parameters such as signed handoffs. A pool member sees the
59
+ [member page](#use-the-member-page) on every path.
60
+
61
+ ### Overview
62
+
63
+ - **Status pill.** "N need attention" (red when a connector is failing) or
64
+ "All healthy". No pill without connectors.
65
+ - **Stat tiles.** Connectors (healthy of total, a bar with one segment per
66
+ connector in its health color), Endpoints (count, a bar split read-only and
67
+ read-write), and People · Agents (both counts, up to eight avatars and agent
68
+ marks; a tokenless agent's mark is hollow). A dot legend counts each segment
69
+ kind; the first two tiles link to their pages. At 760px and below the tiles
70
+ sit two up, with People · Agents as one row across both.
71
+ - **Needs attention.** One row per connector whose health is not ok, in
72
+ configuration order, then one per agent in a pool whose token is missing or revoked. A
73
+ row names the problem ("crm needs authorization"), the endpoints it
74
+ affects ("Affects /mcp and /mcp/team") or the agent URL it can't connect at,
75
+ and links to the existing fix: Connect, Replace key or Inspect on
76
+ the connector's Connection tab, or Issue token on Tokens. A row with a
77
+ problem code also has Copy fix prompt. A problem keeps its row and
78
+ prompt when the connector's detail read failed, prefixed "Details didn't
79
+ load". Surviving connector rows retain their order as individual reads settle,
80
+ even when their severity changes. With no rows it reads "All clear".
81
+ - **Who reaches what.** The [connection map](#connection-map).
82
+
83
+ ### Connection map
84
+
85
+ An SVG flow of callers (people in contract order, then declared agents) to
86
+ endpoints (`/mcp`, then pools) to connectors in config order, with a last
87
+ column of each connector's read and write tool counts. A connector whose
88
+ catalog is unknown (failed or not yet observed) draws a muted dash there
89
+ instead of "0 tools".
90
+
91
+ - A grant link takes its connector's health color. Grants on a read-only
92
+ endpoint are dashed; an agent's link to its pool is dotted while it has no
93
+ issued token. Plain `/mcp` admits no agents. A read-only endpoint carries a
94
+ read-only chip.
95
+ - Hovering or focusing a node dims everything off its paths and replaces the
96
+ legend with one sentence, such as "alice reaches 2 connectors through /mcp
97
+ and /mcp/team: 6 tools, 1 write." The sentence is also the node's accessible
98
+ name. Hover wins while both are set.
99
+ - The map is one tab stop. Arrow keys move within a column and to the nearest
100
+ node in the next one; Home and End go to the first and last node.
101
+ - Click or Enter opens the node's page: a connector's Tools tab (Connection
102
+ when it needs attention), an endpoint's row on Endpoints, a person's first
103
+ endpoint, or Tokens for an agent when that page is open. A node without a
104
+ page is a `group`.
105
+ - The drawing never scales below 880px; a narrower card scrolls it sideways.
106
+ At 960px and below it becomes a list with one entry per endpoint: its mode,
107
+ its callers as chips that link like map nodes, and its connectors with
108
+ health. With no connectors it reads "Nothing to map yet".
109
+
110
+ ### Endpoints
111
+
112
+ One row each for `/mcp` and every pool: the path, a read-only pill on a
113
+ read-only endpoint, a copyable URL, who can use it, its connectors as colored
114
+ monograms (four, then "+N"), its tool count over a read and write bar, and a
115
+ Setup button.
116
+
117
+ - Who can use it is `root.maintainers` on `/mcp` and the pool's `members`
118
+ elsewhere, as an avatar stack named on hover and to screen readers (label,
119
+ raw id when the label is null, or agent name). Four show, then a "+N"
120
+ button. A pool with agent members labels its two URLs People and Agents.
121
+ - Expanding a row lists everyone by name, then each connector with what it
122
+ runs as and its tools, write tools amber with a pencil. Runs-as comes from
123
+ the endpoint's matrix cell: "Shared · saved <date>", "Shared · connected
124
+ <date>", "Shared · not configured", "Shared · set in deployment", "Shared ·
125
+ no credential needed", "Personal · N of M connected", "Workspace · people:
126
+ self · agents: <owner>" (or "none"), or "Everyone acts as <subject>".
127
+ - A connector that needs attention gets a status dot on its monogram and
128
+ beside its name, linking to its Connection tab.
129
+ - Setup opens a drawer with the URL and a Claude Code, Codex or JSON snippet
130
+ with a copy button. No snippet carries a token.
131
+
132
+ Counts intersect live tools with the pool's declared tools (the `/mcp` matrix
133
+ cells for the root), guarded grants' live verdicts, and read-only mode.
134
+
135
+ ### Connectors
136
+
137
+ One card per connector: title and id, one status pill, a Shared or Per person
138
+ badge, a Read-only badge when connector `readOnly` is enabled, its tool count over a read and write bar, and when it was last called.
139
+ All, Needs attention and Healthy filter the cards, with counts, beside a
140
+ search field. A connector that is not fine adds one action (Connect, Replace
141
+ key or Inspect) that opens its Connection tab.
142
+
143
+ Every view shares one verdict per connector: the server's problem code first
144
+ (a failed catalog reads "Catalog failed", never "Connected"), then a failed
145
+ detail read ("Couldn't load", with no fix prompt), then a non-ok status.
146
+ Catalog drift is informational: it stays in the connector's Connection panel
147
+ with its fix prompt and in Activity, and never affects health or attention.
148
+
149
+ Health does not bounce while details load. A connector whose detail read is
150
+ in flight (its `/ui/data` row is `loading`, during sign-in, Retry or a
151
+ connector's Refresh) keeps the verdict the page last showed for it on every
152
+ view (cards, filter counts, the Overview headline, bar, attention list and map,
153
+ Endpoints and the connector page) until that read settles, never "Loading
154
+ details" or an in-between verdict. A connector with no earlier verdict shows
155
+ its contract status. Each connector changes only when its own read settles,
156
+ so one slow read never holds back the others and no row moves for an
157
+ in-between verdict. A new signed-in identity starts fresh. Cards reserve the action footer
158
+ even when no action is needed and the tool bar row even when the catalog is
159
+ empty. Each card header keeps its title, status and id/scope badges on single
160
+ lines; long text truncates with ellipsis and retains its full value on hover
161
+ and for screen readers. The connector detail header and Overview attention
162
+ text follow the same rule, and truncated links remain keyboard focusable.
163
+ Wider status labels never change the card height.
164
+
165
+ The top bar uses an icon-only Search button (⌘K or Ctrl+K opens the palette).
166
+ Deployment names stay on one line with ellipsis and their full name on hover;
167
+ a name matching the product label is omitted. Tabs scroll horizontally when
168
+ needed, moving to a second row on narrow screens.
169
+
170
+ A List / Matrix toggle (`?view=matrix`) switches to a table of connectors by
171
+ endpoint, `/mcp` first. A row header is the connector's monogram and name, plus
172
+ a status dot linking to Connection when it needs fixing. Each cell is a pie of
173
+ how much of the live catalog it grants, with "all", a count, or a dash for
174
+ none; read-only columns are hatched. Only granted names still in the live
175
+ catalog count. An unknown catalog shows a dashed empty ring and "?". A cell
176
+ with grants is a button named like "GitHub on /mcp/support: 1 of 2 live
177
+ tools, read-only"; it opens a popover of that cell's tools, each with a read
178
+ or write pill (a write struck through on a read-only endpoint), and its
179
+ runs-as. Escape or Tab returns focus to the cell. CSS anchor positioning
180
+ places the popover below the cell, or above when there is more room, and the
181
+ page sets no inline styles. Without anchor support the same list opens as a
182
+ row under the connector.
183
+
184
+ ### Connector detail
185
+
186
+ The title, status pill, id, auth badge and read and write bar, then three
187
+ tabs:
188
+
189
+ - **Tools.** Each tool by its mono address with a Read or Write badge and
190
+ annotation badges (Destructive, Open world), filtered by search and All,
191
+ Read and Write. A tool opens its schema in a side drawer.
192
+ - **Connection.** An Authentication card (mode, OAuth client mechanism, who
193
+ manages it, OAuth actions, and the credential card with masked last four,
194
+ field states, and Replace, Test and Remove); a Diagnostics card of tiles
195
+ (catalog age, last call, drift counts) with a fix prompt beside each
196
+ problem; and a Configuration card. Its badges name the kind (Remote MCP,
197
+ HTTP API or Custom), provider, auth scope, endpoint host and usage guide.
198
+ The auth row names the mode and draws each auth fact as a mono badge
199
+ (credential fields, header and scheme, static header names, OAuth scope, API
200
+ origins as `→ api.crm.example`, OAuth endpoints, client metadata host,
201
+ token auth method, Client secret, PKCE, extra parameter and header names).
202
+ Tiles follow for the result cap, call admission rules and transport. Any
203
+ other key becomes a tile labelled from its name.
204
+ - **Activity.** The [Activity](#activity) page for that connector, without
205
+ connector chips or monograms.
206
+
207
+ #### Read catalog drift
208
+
209
+ The connector's drift panel reports the last catalog comparison in this
210
+ runtime and identity partition. It never lists tool names or schemas. A
211
+ personal OAuth refresh belongs to that user; another user or endpoint subject
212
+ does not inherit it. A runtime restart or bounded observation eviction resets
213
+ the report until another listing is served.
214
+
215
+ “No catalog refresh yet” means this partition has no observation. “No reviewed
216
+ baseline” means a listing was observed without a reviewed classification.
217
+ “Matches the reviewed manifest” requires a baseline, successful verification,
218
+ no differences, and schema pins for every live reviewed tool. “Schemas not
219
+ pinned” and “Partial schema coverage” describe missing review evidence; they
220
+ are not clean schema comparisons. “Schema verification unavailable” replaces
221
+ an earlier successful report if hashing fails. Known differences remain visible
222
+ alongside coverage or verification limits. Each operator refresh returns the
223
+ comparison from the catalog it just loaded, including hashing failures and
224
+ schema changes, without another downstream status probe.
225
+
226
+ The unserved count excludes reviewed names explicitly marked optional for
227
+ plan, feature, or permission gating. Present optional tools still participate
228
+ in annotation and schema comparisons. Dropped tool names are counted even
229
+ without a baseline, and do not establish one.
230
+
231
+ ### Settings
232
+
233
+ The configuration snapshot as tiles, tagged "Defined in code", with no
234
+ editing controls. An empty section is not drawn.
235
+
236
+ - **Deployment.** Fact chips: name and version (`Production · v1`), Writes
237
+ allowed or Read-only, connecta version, public URL, allowed origins,
238
+ sandbox, storage, activity store, deployment ID, website, icon count and
239
+ `deploymentInfo` keys. Default memory storage reads "Memory · default" as a
240
+ warning: on Node a restart loses it.
241
+ - **Sign-in.** One tile per inbound auth provider in the order they are tried,
242
+ with its mark and whether it admits people or machines; the agent-token
243
+ tile counts agents ("3 agents"). Then a Maintainers tile with the `/mcp`
244
+ maintainers, or "None". With no providers an Open tile comes first.
245
+ - **Features.** Vault ("Seals OAuth" when it does), activity, agent tokens
246
+ and any other module, on or off.
247
+ - **Limits.** Each limit as a value over a short label: durations in their
248
+ largest whole unit, sizes in decimal KB or MB with exact bytes as a
249
+ tooltip, counts with separators, "No limit", and On or Off. A null tool
250
+ timeout shows the host-call timeout it falls back to. Headline limits and
251
+ any limit set in code draw large. The rest sit behind one disclosure
252
+ ("17 defaults") with Discovery, Results, Programs and Requests groups. A
253
+ value set in code (by `configSources`) has an accent dot; a default reads
254
+ muted. Activity retention counts as set only when the activity store
255
+ reports `optionSources.retentionDays` as `"config"`, as the shipped D1 and
256
+ SQLite stores do.
257
+ - **Overrides.** Each classification override as tool address and verdict.
258
+ - **Other.** Any snapshot key Settings does not map, as a tile labelled from
259
+ its name, set only when its value carries `source: "config"`.
260
+
261
+ ### Tokens
262
+
263
+ One row per agent declared in code, in `GET /ui/access-tokens` order: agent
264
+ mark and name, pools as chips, a state pill (No token, Issued or Revoked), the
265
+ issue or revoke date, and last seen ("never" when null). The heading note
266
+ reads "Declared in code"; nothing creates or renames an agent. Narrow screens
267
+ stack each row into a card.
268
+
269
+ - Issue appears for a slot with no token or a revoked one; Rotate and a quiet
270
+ red Revoke for an issued one. Rotate and Revoke ask first in a row under the
271
+ agent, with focus on Cancel.
272
+ - Every mutation sends `{ "expect": "<revision>" }` with the slot revision the
273
+ operator saw. A new secret opens once in a dialog with a copy button and
274
+ "You won't see this token again."; closing it drops the secret, and
275
+ recovery never closes it.
276
+ - A 409 `slot_changed` reads "Changed since you looked. Refresh." A 503
277
+ `outcome_unknown` or 499 `aborted` is a failure notice and is never
278
+ retried.
279
+ - A sent mutation leaves its slot unresolved until its successful response is
280
+ validated. Any other outcome, a contract whose `agents[].token` disagrees
281
+ with the list (revision included) or drops the agent, or a failed read
282
+ leaves it unresolved until a later slot-list read succeeds. Until then its
283
+ controls are off with "Refresh to continue", and each action is checked
284
+ again just before it is sent.
285
+ - Under the recovery banner Tokens has no Refresh or list Retry of its own,
286
+ and an open rotate or revoke question closes.
287
+
288
+ ### Activity
289
+
290
+ Counts for the loaded history (calls, failed, tools, catalog changes), also
291
+ in its accessible summary, and a strip of calls over time with failures in
292
+ red when the calls span more than a minute.
293
+
294
+ - **Filters.** One bar: search, All / Failed / Succeeded (`?outcome=failed`
295
+ keeps errors and timeouts, `?outcome=succeeded` successes and approvals),
296
+ and chips for each loaded connector and source (`?connector=`, `?source=`).
297
+ Pressing a pressed chip clears it, and a selected value keeps its chip.
298
+ Another `?outcome=` value matches exactly and shows as a clearable Exact
299
+ outcome chip.
300
+ - **Rows.** Grouped by recorded request id on a shared rail. Each shows a
301
+ status dot, time, caller (a person by label or id with initials, an agent
302
+ by name with its mark, anything else by kind), connector monogram and tool
303
+ address, a write tag, the failure reason, and duration and size. Opening a
304
+ row lists what was recorded: result, how it ran, classification, exact
305
+ duration and size, caller, stable caller id, request id, client, and
306
+ connecta version. Unrecorded fields are left out. Catalog changes are rows
307
+ with added, removed and changed counts.
308
+ - **Empty.** "No calls yet" with Refresh, or "No matches" with Clear filters.
309
+
310
+ ### Navigation, gates and recovery
311
+
312
+ The top bar is one row: the mark, branding and deployment name, the section
313
+ links (Overview, Endpoints, Connectors, Activity, Tokens, Settings), then
314
+ icon-only Search (the command palette, also ⌘K or Ctrl+K), Appearance, and Account
315
+ (the signed-in account with Sign out or Change token). The mark is connecta's
316
+ drawn "C" only when no product name, owner or favicon is configured; with
317
+ `branding.favicon.svg` it is that SVG; otherwise there is none. The sign-in
318
+ gate shows the same mark above "Sign in". Below 820px the section links move
319
+ to a second row that scrolls sideways and keeps the current section in view,
320
+ with Search remaining an icon. A member's top bar has only branding and
321
+ Account. The command palette searches visible pages, connectors and tools,
322
+ opening connector results on Tools.
323
+
324
+ `GET /ui/api/config` is the browser's one gate: a 401 shows sign-in, the
325
+ private 404 shows "No access" with who to ask and Sign out or Change token,
326
+ and a 200 renders by `role`. `/ui/data`, connector details, activity and
327
+ tokens are requested only after the contract says `maintainer`, and each read
328
+ checks the role again when it is sent. Until a role is confirmed the page
329
+ shows its loading or error state and no navigation. Activity and Tokens keep
330
+ their own permission gates.
331
+
332
+ The store keeps the last confirmed role through a failed refresh: a
333
+ maintainer's page stays mounted, inert and dimmed, under one shell banner
334
+ ("Couldn't load configuration" with Retry), and sends nothing maintainer-only
335
+ until a contract confirms the role again. Recovery closes the page's dialogs,
336
+ drawers, popovers and the command palette, and moves focus to Retry.
337
+ Credential and OAuth writes also wait for a contract that agrees with the
338
+ confirmed role: a maintainer's for a connector it shows, a member's for a
339
+ personal connector whose `manage` lists that action. Otherwise the write is
340
+ not sent and its row says so. An answer with a different role clears
341
+ everything read under the old one.
342
+
111
343
  ## Use the member page
112
344
 
113
345
  With `operatorUi()` enabled, sign in at the deployment's public URL using
114
346
  Clerk (Node) or Cloudflare Access (Workers). A person listed in a pool's
115
347
  `members` can open the page without becoming a maintainer. The page, **Your
116
- connections**, has no tabs; its top bar shows branding, the signed-in account
117
- (Clerk's primary email, when there is one) and Sign out or Change token. It
118
- lists:
348
+ connections**, has no tabs; its heading shows the signed-in email when the
349
+ sign-in exposes one (Clerk's primary email), and its top bar shows branding and
350
+ an **Account** button with Sign out or Change token. It lists:
119
351
 
120
- - **Your endpoints**: each admitted `/mcp/<pool>` URL with a copy button and
121
- **Client setup**. For example, Bob in pool `team` copies
352
+ - **Your endpoints**: one card per admitted `/mcp/<pool>` URL with a copy button
353
+ and **Client setup**. For example, Bob in pool `team` copies
122
354
  `https://connecta.example.com/mcp/team` into an MCP client and authenticates
123
355
  as Bob.
124
- - **Your accounts**: the personal connectors in their pools, each with one
125
- status badge and only the controls its `manage.actions` lists. An OAuth
126
- connector offers Connect, Reconnect or Disconnect; Reconnect and Disconnect
127
- ask first. A credential connector offers **Add credential** when only `save`
128
- is listed, and Replace, Test and Clear once a value is stored.
356
+ - **Your accounts**: the personal connectors in their pools, each with a
357
+ monogram, tool count, one status badge in an aligned column, and only the
358
+ controls its `manage.actions` lists. A saved credential that no longer fits
359
+ or does not work adds a short note beside the tool count. An OAuth connector
360
+ offers Connect, Reconnect or Disconnect; Reconnect and Disconnect ask first.
361
+ A credential connector offers **Add credential** when only `save` is listed,
362
+ and Replace, Test and Clear once a value is stored; Clear asks first.
129
363
  - **Shared with you**: shared connectors by name and tool count, without status.
130
364
 
131
365
  Every browser path shows that same member page; it does not expose maintainer
@@ -160,8 +394,9 @@ only gate: a signed-out caller gets the auth provider's 401 challenge, and a
160
394
  `cta_` agent token the machine-only 401 Bearer challenge every human route
161
395
  gives it; a maintainer, or a person listed in a pool's `members`, gets 200
162
396
  with `role` `"maintainer"` or `"member"`; anyone else gets the private JSON 404
163
- `{ "error": "not found" }`. An open deployment's anonymous caller is
164
- a maintainer. Every response is private, `no-store` JSON, and only GET is
397
+ `{ "error": "not found" }`. An open deployment's anonymous caller gets
398
+ `role: "maintainer"` but has no principal: activity is `"forbidden"`, the
399
+ activity and access-token routes answer 404, and owners are `null`. Every response is private, `no-store` JSON, and only GET is
165
400
  allowed. One shape serves both roles; a field a role does not receive is
166
401
  `null` or empty, never omitted.
167
402
 
@@ -193,7 +428,8 @@ The maintainer view carries:
193
428
  pool that serves it, with that endpoint's tool names or `"all"` and
194
429
  `runsAs`. A Workspace connector with a subject mapping is
195
430
  `{ kind: "workspace", humans: "self", agents }`, `agents` being the pool's
196
- owner, or `null` on plain `/mcp` and in an ownerless pool; a fixed subject is
431
+ owner, or `null` on plain `/mcp` and in an ownerless pool, where agents do
432
+ not see the connector at all; a fixed subject is
197
433
  `{ kind: "workspaceFixed", subject }`. A personal connector counts the
198
434
  endpoint's people (the maintainers on plain `/mcp`) and how many have
199
435
  connected in their own partition: a stored credential of the declared shape,
@@ -273,7 +509,7 @@ existing doctor authentication environment variables; it runs no diagnostic
273
509
  program, follows no redirects, and prints no raw HTTP failure body.
274
510
 
275
511
  The operator shell uses React, TanStack Router/Query/Table, Radix, cmdk and
276
- Tailwind v4. Geist Sans, Geist Mono, CSS, JavaScript and dependency notices are hashed assets
512
+ Tailwind v4. Hanken Grotesk, JetBrains Mono, CSS, JavaScript and dependency notices are hashed assets
277
513
  under `/ui/assets/*`, served identically with immutable cache headers on Node
278
514
  and Workers. HTML contains only mount points and escaped inert configuration;
279
515
  it remains uncached. Ahead of the stylesheet, every operator page (sign-in
@@ -334,7 +570,7 @@ A later focus return can request another status read. Recovery never starts OAut
334
570
  or replays a mutation.
335
571
  Unreadable credential metadata uses `configured: null`, including named fields,
336
572
  and renders as unavailable with a retry prompt. It does not claim that the slot
337
- is empty. Endpoints, Connectors, connector
573
+ is empty. Overview, Endpoints, Connectors, connector
338
574
  detail, Settings, and the member page consume the typed contract; Activity opens
339
575
  only to a maintainer whose contract reports readable history. Connector detail
340
576
  reads auth permissions from its `/ui/data` connector. Activity retains
@@ -364,19 +600,6 @@ id and typed actor when available, otherwise a fresh id and system actor. No
364
600
  names, descriptions or schemas enter the event. Private catalog changes require
365
601
  a matching principal owner even when the connector uses shared auth. Empty credential declarations
366
602
  report `credential_required` before running a connector status or catalog probe.
367
- The top bar shows deployment branding and a name breadcrumb, then Search (the
368
- command palette), Appearance, and the session action (Change token or Sign out)
369
- at one quiet size; a member's top bar has only branding, the account and the
370
- session action. The tab row lists Endpoints, Connectors, Activity,
371
- Tokens, and Settings. Activity and Tokens keep their permission gates; a gated
372
- viewer sees no operator navigation. The command palette searches visible pages,
373
- connectors and tools, opening connector results on Tools. `/access` redirects
374
- to `/`, `/tools` to `/connectors`, and `/config` to `/settings` in the browser
375
- with history replacement. Connector hashes `#config`, `#auth` and `#diagnostics`
376
- redirect to `#connection`, preserving query parameters such as signed handoffs.
377
- Token controls retain their existing permission gate.
378
- Configuration remains in deployment code. The UI mutates only credentials,
379
- OAuth connections and agent tokens through the existing routes.
380
603
 
381
604
  ## Contributor reference
382
605
 
@@ -390,6 +613,20 @@ projection built from config, membership, the member's own partition status,
390
613
  and each personal connector's exact `manage`;
391
614
  `test/operator-contract-server.test.ts` runs it against real responses.
392
615
 
616
+ The Overview's map and attention rows are pure functions of the contract in
617
+ [connection-map.ts](https://github.com/zackbart/connecta/blob/main/src/operator-ui/connection-map.ts)
618
+ and [overview.ts](https://github.com/zackbart/connecta/blob/main/src/operator-ui/overview.ts),
619
+ covered by `test/operator-connection-map.test.ts` and
620
+ `test/operator-overview.test.ts`; `src/operator-ui/styles/overview.css` holds
621
+ the page's styles.
622
+
623
+ `src/operator-ui/config-summary.ts` maps the snapshot and its provenance to
624
+ those tiles: one table of limit labels, the formatters, and the walk that turns
625
+ an unmapped key into an Other tile. `app/config-tiles.tsx` draws them, and
626
+ `test/operator-config-summary.test.ts` checks formatting, provenance, unknown
627
+ keys, an empty deployment, and that a real deployment's snapshot leaves no key
628
+ unmapped.
629
+
393
630
  The contract type is [contract.ts](https://github.com/zackbart/connecta/blob/main/src/operator-ui/contract.ts).
394
631
  [UI routes](https://github.com/zackbart/connecta/blob/main/src/routes/ui.ts) and
395
632
  [UI implementation](https://github.com/zackbart/connecta/blob/main/src/ui.ts)
@@ -13,6 +13,28 @@ uses one implementation: configure two ids for both.
13
13
 
14
14
  ## Stripe
15
15
 
16
+ ## Choose OAuth or an API key
17
+
18
+ Import `stripe` from `@zackbart/connecta/providers/stripe`. Choose one of two setup paths:
19
+
20
+ ```ts
21
+ // OAuth: Stripe's hosted MCP. Authorize the connection with Stripe.
22
+ stripe("billing", { purpose: "Payments", auth: { type: "oauth" } });
23
+ stripe("billing", { purpose: "Revenue reports", auth: { type: "oauth" }, readOnly: true });
24
+
25
+ // API key: Connecta's REST connector. Paste the key into this connection in the operator UI.
26
+ stripe("billing", { purpose: "Payments", auth: { type: "apiKey" }, mode: "production" });
27
+ stripe("billing", { purpose: "Revenue reports", auth: { type: "apiKey" }, mode: "production", readOnly: true });
28
+ ```
29
+
30
+ For an API key, set `mode` to `"production"` or `"sandbox"` to match the key.
31
+ Use a secret (`sk_`) or restricted (`rk_`) key. For read-only access, prefer a
32
+ restricted `rk_` key configured with only read permissions: Stripe enforces
33
+ those permissions too. Connecta's `readOnly: true` omits non-read tools and
34
+ refuses their calls on every endpoint. Omit it for the default writable connector;
35
+ endpoint restrictions still apply. OAuth needs no `mode` and can reach both live
36
+ and sandbox accounts through Stripe's account selectors.
37
+
16
38
  Stripe's hosted MCP server stops accepting secret keys and untagged
17
39
  restricted keys on 2026-10-31; Stripe still documents agent-tagged restricted
18
40
  keys for it. Connecta's hosted Stripe connection is OAuth only either way, and
@@ -72,7 +72,7 @@ tokens, upgrading, and diagnosis with `connecta doctor` to their procedures.
72
72
  `CF_ACCESS_CLIENT_ID`, `CF_ACCESS_CLIENT_SECRET`, and `CONNECTA_TOKEN`
73
73
  together, and pass `--pool ci`, a pool that lists the agent.
74
74
  Machine clients are the `agents` declared in `src/connecta.config.ts`. Issue
75
- or rotate a token through the Access-authenticated operator page or trusted
75
+ or rotate a token through the operator Tokens page as a signed-in maintainer or trusted
76
76
  `AccessTokenManager.rotate` tooling against this same D1 storage, as README
77
77
  "Machine tokens" describes. Never configure a static bearer or open startup.
78
78
  UI, vault, and activity use explicit optional imports;
@@ -80,20 +80,26 @@ tokens, upgrading, and diagnosis with `connecta doctor` to their procedures.
80
80
  - Organize agent pools by connecta's agent pool layout:
81
81
  `node_modules/@zackbart/connecta/documentation/auth.md#organizing-an-agents-pools`
82
82
  ([online](https://github.com/zackbart/connecta/blob/main/documentation/auth.md#organizing-an-agents-pools)).
83
- Each agent keeps one Connecta connection whose client picks the pool per
84
- turn: base pool `<agent>` (shared connectors, no `owner`) outside a
85
- one-on-one, and `<agent>-<user>` (the base plus that user's own connector
86
- ids, `owner` set to their Workspace address) only with that user. Never list
87
- another person in a `<agent>-<user>` pool: its per-user connectors act as
88
- that user for every member. Never add a second Connecta connection or mount
89
- downstream tools directly.
83
+ Each agent keeps one Connecta connection whose harness, never the model,
84
+ picks the pool per turn. Tiers are nested pools of shared connectors with
85
+ no `owner`, each spreading the tool list below. Recommended names are
86
+ `<agent>` for the lowest and `<agent>-<tier>` above it; any named pool,
87
+ including an existing `team` or `leadership` pool, may be a tier if all its
88
+ human members are cleared for it. A chat gets the most capable tier everyone
89
+ present is cleared for, and the lowest when anyone present is unknown.
90
+ `<agent>-<user>` (that user's highest tier plus their own connector ids,
91
+ `owner` set to their Workspace address) is used only in a one-on-one with
92
+ that user. List only cleared people in a tier, and never another person in
93
+ a `<agent>-<user>` pool: its per-user connectors act as that user for every
94
+ member. Never add a second Connecta connection or mount downstream tools
95
+ directly.
90
96
  - Brand the operator UI in `operatorUi({ branding })`: product and owner names,
91
97
  description, favicon, and `theme` (`accent`, `radius`, `fontFamily`,
92
98
  `monoFamily`, `colorScheme`). Ask the deployment's owner for their brand
93
99
  rather than leaving the default. README "UI and encrypted credentials" shows
94
100
  the shape.
95
101
  - After configuration changes, typecheck: inside the connecta repository that
96
- is `npm run check:examples`; a copied deployment runs its own `tsc --noEmit`.
102
+ is `pnpm run check:examples`; a copied deployment runs its own `tsc --noEmit`.
97
103
  After deployment, connect both Claude and ChatGPT to `<PUBLIC_URL>/mcp` and
98
104
  complete their browser authorization flows before calling setup complete.
99
105