@zackbart/connecta 0.15.1 → 0.16.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 (335) hide show
  1. package/AGENTS.md +40 -20
  2. package/CHANGELOG.md +653 -0
  3. package/README.md +25 -5
  4. package/bin/connecta.mjs +44 -3
  5. package/dist/access-tokens.d.ts +0 -1
  6. package/dist/access-tokens.js +0 -1
  7. package/dist/activity.d.ts +50 -2
  8. package/dist/activity.js +34 -1
  9. package/dist/apps-shell.d.ts +0 -1
  10. package/dist/apps-shell.js +0 -1
  11. package/dist/auth/bearer.d.ts +0 -1
  12. package/dist/auth/bearer.js +0 -1
  13. package/dist/auth/clerk.d.ts +0 -1
  14. package/dist/auth/clerk.js +45 -9
  15. package/dist/auth/downstream-oauth.d.ts +0 -1
  16. package/dist/auth/downstream-oauth.js +0 -1
  17. package/dist/call-admission.d.ts +0 -1
  18. package/dist/call-admission.js +0 -1
  19. package/dist/catalog-drift.d.ts +99 -0
  20. package/dist/catalog-drift.js +251 -0
  21. package/dist/catalog-fingerprint.d.ts +0 -1
  22. package/dist/catalog-fingerprint.js +0 -1
  23. package/dist/catalog-limits.d.ts +0 -1
  24. package/dist/catalog-limits.js +0 -1
  25. package/dist/catalog-service.d.ts +0 -1
  26. package/dist/catalog-service.js +41 -5
  27. package/dist/catalog.d.ts +11 -1
  28. package/dist/catalog.js +20 -1
  29. package/dist/concurrency.d.ts +0 -1
  30. package/dist/concurrency.js +0 -1
  31. package/dist/connector-scope.d.ts +0 -1
  32. package/dist/connector-scope.js +0 -1
  33. package/dist/connectors/api.d.ts +29 -21
  34. package/dist/connectors/api.js +45 -19
  35. package/dist/connectors/guarded-fetch.d.ts +106 -0
  36. package/dist/connectors/guarded-fetch.js +289 -0
  37. package/dist/connectors/remote-mcp.d.ts +0 -1
  38. package/dist/connectors/remote-mcp.js +0 -1
  39. package/dist/credentials.d.ts +0 -1
  40. package/dist/credentials.js +0 -1
  41. package/dist/errors.d.ts +30 -3
  42. package/dist/errors.js +1 -1
  43. package/dist/execute.d.ts +0 -1
  44. package/dist/execute.js +0 -1
  45. package/dist/executor-admission.d.ts +11 -1
  46. package/dist/executor-admission.js +28 -1
  47. package/dist/executor-result.d.ts +0 -1
  48. package/dist/executor-result.js +0 -1
  49. package/dist/executors/quickjs-child.d.ts +0 -1
  50. package/dist/executors/quickjs-child.js +0 -1
  51. package/dist/executors/quickjs-protocol.d.ts +0 -1
  52. package/dist/executors/quickjs-protocol.js +0 -1
  53. package/dist/executors/quickjs-runtime.d.ts +0 -1
  54. package/dist/executors/quickjs-runtime.js +0 -1
  55. package/dist/executors/quickjs.d.ts +0 -1
  56. package/dist/executors/quickjs.js +2 -1
  57. package/dist/favicon.d.ts +0 -1
  58. package/dist/favicon.js +0 -1
  59. package/dist/index.d.ts +2 -3
  60. package/dist/index.js +24 -7
  61. package/dist/invocation.d.ts +0 -1
  62. package/dist/invocation.js +0 -1
  63. package/dist/json-schema.d.ts +0 -1
  64. package/dist/json-schema.js +0 -1
  65. package/dist/mcp-result.d.ts +0 -1
  66. package/dist/mcp-result.js +0 -1
  67. package/dist/meta-tools.d.ts +0 -1
  68. package/dist/meta-tools.js +0 -1
  69. package/dist/node.d.ts +0 -1
  70. package/dist/node.js +0 -1
  71. package/dist/operator-ui/generated.d.ts +2 -3
  72. package/dist/operator-ui/generated.js +3 -4
  73. package/dist/operator-ui/model.d.ts +10 -1
  74. package/dist/operator-ui/model.js +0 -1
  75. package/dist/operator-ui/view.d.ts +167 -0
  76. package/dist/operator-ui/view.js +270 -0
  77. package/dist/providers/cloudflare.d.ts +0 -1
  78. package/dist/providers/cloudflare.js +261 -299
  79. package/dist/providers/linear.d.ts +26 -5
  80. package/dist/providers/linear.js +32 -61
  81. package/dist/providers/mixpanel.d.ts +35 -4
  82. package/dist/providers/mixpanel.js +53 -79
  83. package/dist/providers/notion.d.ts +0 -1
  84. package/dist/providers/notion.js +87 -42
  85. package/dist/providers/stripe.d.ts +13 -1
  86. package/dist/providers/stripe.js +31 -60
  87. package/dist/registry.d.ts +34 -2
  88. package/dist/registry.js +85 -5
  89. package/dist/retired-toolkits.d.ts +0 -1
  90. package/dist/retired-toolkits.js +0 -1
  91. package/dist/routes/access-tokens.d.ts +0 -1
  92. package/dist/routes/access-tokens.js +0 -1
  93. package/dist/routes/activity.d.ts +0 -1
  94. package/dist/routes/activity.js +0 -1
  95. package/dist/routes/credentials.d.ts +0 -1
  96. package/dist/routes/credentials.js +0 -1
  97. package/dist/routes/mcp.d.ts +0 -1
  98. package/dist/routes/mcp.js +0 -1
  99. package/dist/routes/oauth.d.ts +0 -1
  100. package/dist/routes/oauth.js +0 -1
  101. package/dist/routes/shared.d.ts +2 -1
  102. package/dist/routes/shared.js +0 -1
  103. package/dist/routes/ui.d.ts +0 -1
  104. package/dist/routes/ui.js +0 -1
  105. package/dist/server.d.ts +0 -1
  106. package/dist/server.js +11 -1
  107. package/dist/skills.d.ts +0 -1
  108. package/dist/skills.js +0 -1
  109. package/dist/storage/file.d.ts +0 -1
  110. package/dist/storage/file.js +0 -1
  111. package/dist/storage/memory.d.ts +0 -1
  112. package/dist/storage/memory.js +0 -1
  113. package/dist/timeout.d.ts +0 -1
  114. package/dist/timeout.js +0 -1
  115. package/dist/tool-safety.d.ts +0 -1
  116. package/dist/tool-safety.js +0 -1
  117. package/dist/types.d.ts +45 -1
  118. package/dist/types.js +0 -1
  119. package/dist/ui.d.ts +0 -1
  120. package/dist/ui.js +13 -137
  121. package/dist/validate.d.ts +13 -15
  122. package/dist/validate.js +24 -11
  123. package/dist/version.d.ts +1 -2
  124. package/dist/version.js +1 -2
  125. package/documentation/architecture.md +186 -5
  126. package/documentation/auth.md +11 -0
  127. package/documentation/call-admission.md +142 -6
  128. package/documentation/cloudflare.md +92 -10
  129. package/documentation/code-first-exploration.md +2 -2
  130. package/documentation/code-mode.md +14 -14
  131. package/documentation/connector-guides.md +172 -5
  132. package/documentation/connectors.md +89 -0
  133. package/documentation/linear.md +20 -2
  134. package/documentation/mcp-ui-design.md +2 -2
  135. package/documentation/meta-tools.md +7 -1
  136. package/documentation/mixpanel.md +42 -9
  137. package/documentation/notion.md +23 -2
  138. package/documentation/operations.md +325 -5
  139. package/documentation/operator-ui.md +120 -5
  140. package/documentation/provider-audit.md +160 -0
  141. package/documentation/provider-conventions.md +667 -0
  142. package/documentation/request-admission.md +167 -5
  143. package/documentation/rich-output-design.md +1 -2
  144. package/documentation/stripe.md +15 -0
  145. package/documentation/upgrading.md +454 -0
  146. package/ethos.md +14 -9
  147. package/examples/worker/README.md +102 -12
  148. package/examples/worker/src/index.ts +46 -1
  149. package/examples/worker/wrangler.jsonc +14 -1
  150. package/package.json +10 -6
  151. package/templates/node/.dockerignore +10 -0
  152. package/templates/node/.env.example +40 -3
  153. package/templates/node/AGENTS.md +16 -1
  154. package/templates/node/Dockerfile +49 -0
  155. package/templates/node/README.md +117 -2
  156. package/templates/node/docker-compose.yml +39 -0
  157. package/templates/node/package.json +1 -1
  158. package/templates/node/src/file-activity.ts +182 -0
  159. package/templates/node/src/index.ts +80 -4
  160. package/assets/connecta-clay-hero.png +0 -0
  161. package/dist/access-tokens.d.ts.map +0 -1
  162. package/dist/access-tokens.js.map +0 -1
  163. package/dist/activity.d.ts.map +0 -1
  164. package/dist/activity.js.map +0 -1
  165. package/dist/apps-shell.d.ts.map +0 -1
  166. package/dist/apps-shell.js.map +0 -1
  167. package/dist/auth/bearer.d.ts.map +0 -1
  168. package/dist/auth/bearer.js.map +0 -1
  169. package/dist/auth/clerk.d.ts.map +0 -1
  170. package/dist/auth/clerk.js.map +0 -1
  171. package/dist/auth/downstream-oauth.d.ts.map +0 -1
  172. package/dist/auth/downstream-oauth.js.map +0 -1
  173. package/dist/call-admission.d.ts.map +0 -1
  174. package/dist/call-admission.js.map +0 -1
  175. package/dist/catalog-fingerprint.d.ts.map +0 -1
  176. package/dist/catalog-fingerprint.js.map +0 -1
  177. package/dist/catalog-limits.d.ts.map +0 -1
  178. package/dist/catalog-limits.js.map +0 -1
  179. package/dist/catalog-service.d.ts.map +0 -1
  180. package/dist/catalog-service.js.map +0 -1
  181. package/dist/catalog.d.ts.map +0 -1
  182. package/dist/catalog.js.map +0 -1
  183. package/dist/concurrency.d.ts.map +0 -1
  184. package/dist/concurrency.js.map +0 -1
  185. package/dist/connector-scope.d.ts.map +0 -1
  186. package/dist/connector-scope.js.map +0 -1
  187. package/dist/connectors/api.d.ts.map +0 -1
  188. package/dist/connectors/api.js.map +0 -1
  189. package/dist/connectors/remote-mcp.d.ts.map +0 -1
  190. package/dist/connectors/remote-mcp.js.map +0 -1
  191. package/dist/credentials.d.ts.map +0 -1
  192. package/dist/credentials.js.map +0 -1
  193. package/dist/errors.d.ts.map +0 -1
  194. package/dist/errors.js.map +0 -1
  195. package/dist/execute.d.ts.map +0 -1
  196. package/dist/execute.js.map +0 -1
  197. package/dist/executor-admission.d.ts.map +0 -1
  198. package/dist/executor-admission.js.map +0 -1
  199. package/dist/executor-result.d.ts.map +0 -1
  200. package/dist/executor-result.js.map +0 -1
  201. package/dist/executors/quickjs-child.d.ts.map +0 -1
  202. package/dist/executors/quickjs-child.js.map +0 -1
  203. package/dist/executors/quickjs-protocol.d.ts.map +0 -1
  204. package/dist/executors/quickjs-protocol.js.map +0 -1
  205. package/dist/executors/quickjs-runtime.d.ts.map +0 -1
  206. package/dist/executors/quickjs-runtime.js.map +0 -1
  207. package/dist/executors/quickjs.d.ts.map +0 -1
  208. package/dist/executors/quickjs.js.map +0 -1
  209. package/dist/favicon.d.ts.map +0 -1
  210. package/dist/favicon.js.map +0 -1
  211. package/dist/index.d.ts.map +0 -1
  212. package/dist/index.js.map +0 -1
  213. package/dist/invocation.d.ts.map +0 -1
  214. package/dist/invocation.js.map +0 -1
  215. package/dist/json-schema.d.ts.map +0 -1
  216. package/dist/json-schema.js.map +0 -1
  217. package/dist/mcp-result.d.ts.map +0 -1
  218. package/dist/mcp-result.js.map +0 -1
  219. package/dist/meta-tools.d.ts.map +0 -1
  220. package/dist/meta-tools.js.map +0 -1
  221. package/dist/node.d.ts.map +0 -1
  222. package/dist/node.js.map +0 -1
  223. package/dist/operator-ui/generated.d.ts.map +0 -1
  224. package/dist/operator-ui/generated.js.map +0 -1
  225. package/dist/operator-ui/model.d.ts.map +0 -1
  226. package/dist/operator-ui/model.js.map +0 -1
  227. package/dist/providers/cloudflare.d.ts.map +0 -1
  228. package/dist/providers/cloudflare.js.map +0 -1
  229. package/dist/providers/linear.d.ts.map +0 -1
  230. package/dist/providers/linear.js.map +0 -1
  231. package/dist/providers/mixpanel.d.ts.map +0 -1
  232. package/dist/providers/mixpanel.js.map +0 -1
  233. package/dist/providers/notion.d.ts.map +0 -1
  234. package/dist/providers/notion.js.map +0 -1
  235. package/dist/providers/stripe.d.ts.map +0 -1
  236. package/dist/providers/stripe.js.map +0 -1
  237. package/dist/registry.d.ts.map +0 -1
  238. package/dist/registry.js.map +0 -1
  239. package/dist/retired-toolkits.d.ts.map +0 -1
  240. package/dist/retired-toolkits.js.map +0 -1
  241. package/dist/routes/access-tokens.d.ts.map +0 -1
  242. package/dist/routes/access-tokens.js.map +0 -1
  243. package/dist/routes/activity.d.ts.map +0 -1
  244. package/dist/routes/activity.js.map +0 -1
  245. package/dist/routes/credentials.d.ts.map +0 -1
  246. package/dist/routes/credentials.js.map +0 -1
  247. package/dist/routes/mcp.d.ts.map +0 -1
  248. package/dist/routes/mcp.js.map +0 -1
  249. package/dist/routes/oauth.d.ts.map +0 -1
  250. package/dist/routes/oauth.js.map +0 -1
  251. package/dist/routes/shared.d.ts.map +0 -1
  252. package/dist/routes/shared.js.map +0 -1
  253. package/dist/routes/ui.d.ts.map +0 -1
  254. package/dist/routes/ui.js.map +0 -1
  255. package/dist/server.d.ts.map +0 -1
  256. package/dist/server.js.map +0 -1
  257. package/dist/skills.d.ts.map +0 -1
  258. package/dist/skills.js.map +0 -1
  259. package/dist/storage/file.d.ts.map +0 -1
  260. package/dist/storage/file.js.map +0 -1
  261. package/dist/storage/memory.d.ts.map +0 -1
  262. package/dist/storage/memory.js.map +0 -1
  263. package/dist/timeout.d.ts.map +0 -1
  264. package/dist/timeout.js.map +0 -1
  265. package/dist/tool-safety.d.ts.map +0 -1
  266. package/dist/tool-safety.js.map +0 -1
  267. package/dist/types.d.ts.map +0 -1
  268. package/dist/types.js.map +0 -1
  269. package/dist/ui.d.ts.map +0 -1
  270. package/dist/ui.js.map +0 -1
  271. package/dist/validate.d.ts.map +0 -1
  272. package/dist/validate.js.map +0 -1
  273. package/dist/version.d.ts.map +0 -1
  274. package/dist/version.js.map +0 -1
  275. package/examples/node/README.md +0 -52
  276. package/examples/node/src/index.ts +0 -71
  277. package/src/access-tokens.ts +0 -289
  278. package/src/activity.ts +0 -234
  279. package/src/apps-shell.ts +0 -370
  280. package/src/auth/bearer.ts +0 -61
  281. package/src/auth/clerk.ts +0 -553
  282. package/src/auth/downstream-oauth.ts +0 -575
  283. package/src/call-admission.ts +0 -521
  284. package/src/catalog-fingerprint.ts +0 -52
  285. package/src/catalog-limits.ts +0 -11
  286. package/src/catalog-service.ts +0 -1153
  287. package/src/catalog.ts +0 -790
  288. package/src/concurrency.ts +0 -39
  289. package/src/connector-scope.ts +0 -66
  290. package/src/connectors/api.ts +0 -159
  291. package/src/connectors/remote-mcp.ts +0 -1090
  292. package/src/credentials.ts +0 -428
  293. package/src/errors.ts +0 -364
  294. package/src/execute.ts +0 -1406
  295. package/src/executor-admission.ts +0 -328
  296. package/src/executor-result.ts +0 -107
  297. package/src/executors/quickjs-child.ts +0 -172
  298. package/src/executors/quickjs-protocol.ts +0 -99
  299. package/src/executors/quickjs-runtime.ts +0 -470
  300. package/src/executors/quickjs.ts +0 -776
  301. package/src/favicon.ts +0 -53
  302. package/src/index.ts +0 -666
  303. package/src/invocation.ts +0 -655
  304. package/src/json-schema.ts +0 -11
  305. package/src/mcp-result.ts +0 -43
  306. package/src/meta-tools.ts +0 -1607
  307. package/src/node.ts +0 -206
  308. package/src/operator-ui/browser.css +0 -423
  309. package/src/operator-ui/browser.ts +0 -1281
  310. package/src/operator-ui/generated.ts +0 -4
  311. package/src/operator-ui/model.ts +0 -111
  312. package/src/providers/cloudflare.ts +0 -3999
  313. package/src/providers/linear.ts +0 -302
  314. package/src/providers/mixpanel.ts +0 -229
  315. package/src/providers/notion.ts +0 -1879
  316. package/src/providers/stripe.ts +0 -307
  317. package/src/registry.ts +0 -1085
  318. package/src/retired-toolkits.ts +0 -14
  319. package/src/routes/access-tokens.ts +0 -115
  320. package/src/routes/activity.ts +0 -215
  321. package/src/routes/credentials.ts +0 -254
  322. package/src/routes/mcp.ts +0 -429
  323. package/src/routes/oauth.ts +0 -322
  324. package/src/routes/shared.ts +0 -247
  325. package/src/routes/ui.ts +0 -152
  326. package/src/server.ts +0 -195
  327. package/src/skills.ts +0 -271
  328. package/src/storage/file.ts +0 -123
  329. package/src/storage/memory.ts +0 -44
  330. package/src/timeout.ts +0 -84
  331. package/src/tool-safety.ts +0 -15
  332. package/src/types.ts +0 -523
  333. package/src/ui.ts +0 -744
  334. package/src/validate.ts +0 -387
  335. package/src/version.ts +0 -7
package/ethos.md CHANGED
@@ -38,22 +38,22 @@ order, and amending it is a design decision, not a drive-by edit.
38
38
  - **One fetch-native core, two runtimes.** The same code runs unchanged on
39
39
  Cloudflare Workers and in Node — a Worker or a Docker stack, your pick. Web
40
40
  APIs only in the core; Node touches live behind explicit subpaths.
41
- - **Observable, never administrable.** Operator pages show connector status,
42
- masked credentials, and payload-free activity. They can rotate a secret;
43
- they cannot add a connector, change policy, or alter what an agent can call.
41
+ - **Observable, actionable only over authentication material.** Operator pages
42
+ show connector status, masked credentials, and payload-free activity and
43
+ they act: rotate a credential, issue or revoke an access token, run a
44
+ downstream OAuth flow. Declared capability is what they cannot touch.
44
45
 
45
46
  ## What this isn't
46
47
 
47
48
  - **Not a platform.** No runtime connector registration, no admin UI that
48
- changes behavior, no policy engine, no approvals, no pauses.
49
+ changes declared capability, no policy engine, no approvals, no pauses.
49
50
  - **Not a schema ingester.** No OpenAPI or GraphQL → tools. Generated tool
50
51
  sprawl is the disease the meta-tools treat, not a feature to add.
51
52
  - **Not multi-tenant.** No accounts dimension, no per-user credential store,
52
53
  no org hierarchy. Two accounts on one service are two connector instances.
53
54
  - **Not stateful.** No protocol sessions, no server push. Scope resolves per
54
55
  request — which is also where the MCP spec itself has now arrived.
55
- - **Not a nanny.** Credentials are stored safely and fail loudly at use;
56
- connecta doesn't probe them behind your back.
56
+ - **Not a nanny.** Credentials fail loudly at use; connecta never probes one.
57
57
  - **Not a promise to strangers — yet.** Built for its author's deployments
58
58
  first, published openly. Breaking changes are cheap and the version number
59
59
  signals change, not stability.
@@ -71,6 +71,7 @@ proposing one without a new argument is not.
71
71
  | Runtime connector registration | refused | config-as-code is the security model |
72
72
  | Prebuilt connections as the preferred authoring path | accepted | an a-la-carte provider constructor, imported and constructed in the deployment file, encodes maintained defaults for providers connecta actually uses — preferred *when maintained*, with no promise of one per provider; it returns exactly one ordinary `Connector` with no extra privileges — never a bundle, a group, a preset, or a registry — its tools are hand-written or proxied from a downstream MCP catalog, never generated from a schema document; its vetted annotations classify what the downstream leaves unannotated and otherwise preserve explicit annotations, with one fail-closed exception: a release-reviewed destructive classification outranks a contradictory downstream `readOnlyHint: true`, because Connecta has independently established that the tool mutates existing state; `remoteMcp()` and `api()` stay first-class ([#297](https://github.com/zackbart/connecta/issues/297), [#315](https://github.com/zackbart/connecta/issues/315)) |
73
73
  | Guarded raw REST escape hatches in a prebuilt connection | accepted | a large, fast-moving provider cannot be honestly represented by a small frozen list: a GET-only tool may expose provider-relative reads, while JSON mutations and explicit-content uploads stay separate and always cross the destructive boundary; the connector owns authentication, rate limits, error mapping, URL confinement, and safe method classification, while the provider token remains the capability boundary — this is not schema ingestion, runtime connector registration, or permission widening |
74
+ | Hosted-provider drift detection during catalog refreshes | accepted | a vetted classification is a claim about somebody else's catalog, and an allowlist nobody can tell is stale is an allowlist that is wrong — so each maintained hosted-MCP proxy ships the tool names, classifications, and (once a release records them) schemas it reviewed, and compares them against the live listing *inside* a catalog refresh the deployment already asked for; the boundary is the piggyback itself, which is what keeps this from being proactive credential liveness wearing a new hat ([#179](https://github.com/zackbart/connecta/issues/179)): no scheduled job, no background request, no credential probe, and not one byte of network traffic that would not have happened anyway; what it produces is four counts — unclassified additions, names no longer served, explicit annotation conflicts, schema changes — on connector status, `connecta doctor`, and one payload-free activity event with nowhere to put a tool name or a schema; the two read surfaces answer for the runtime that served the refresh, because the observation is isolate-local and only the activity event is durable, and unknown tools already fail closed, so drift costs approval round trips and stale guidance rather than capability ([#343](https://github.com/zackbart/connecta/issues/343)) |
74
75
  | Provider registry / integration marketplace | refused | prebuilt connections are imports, not listings; discovery happens in documentation, never at runtime ([#297](https://github.com/zackbart/connecta/issues/297)) |
75
76
  | Protocol sessions & server push | refused | stateless per request |
76
77
  | Resources & prompts aggregation | refused | tools only; connecta's own Apps shell is the one `resources/read` carve-out ([#266](https://github.com/zackbart/connecta/issues/266)) |
@@ -80,9 +81,10 @@ proposing one without a new argument is not.
80
81
  | Proactive credential liveness | removed | fail-at-use is enough ([#179](https://github.com/zackbart/connecta/issues/179)) |
81
82
  | Agent credential recovery | accepted | one `auth_required` route through `authorize_connector`; only an operator handles secrets ([#192](https://github.com/zackbart/connecta/issues/192)) |
82
83
  | Operator-issued MCP access tokens | accepted | named, revocable authentication gives header-capable clients a small alternative to OAuth; tokens identify callers but never scope tools or become operator credentials |
84
+ | Operator boundary reworded: authentication material, never declared capability | accepted | supersedes "observable, never administrable", which had stopped describing the surface: operator routes already rotate credentials, issue and revoke access tokens, and drive downstream OAuth, each under its own accepted row, and the owner has decided the surface stays actionable — so the boundary now says what is actually true, that operator routes may manage authentication material for capabilities declared in deployment configuration and may not change the connector set, the declared tool catalog or annotations, requested OAuth scopes, admission policy, authorization rules, or caller tool scope; the claim is deliberately about *declared* capability, and twice so, because replacing an API token with a broader-scoped one widens downstream reach and no browser page can honestly promise otherwise, and because a remote MCP server's catalog is discovered rather than declared — connecta declares the connector, its credential slot, and its admission policy, while the tools that server serves are its own answer, so storing a credential or finishing an OAuth flow can legitimately take an `mcp()` connector from no tools to N, which is discovery arriving, not an operator editing the deployment ([#338](https://github.com/zackbart/connecta/issues/338)) |
83
85
  | Structured result surface | accepted | canonical `structuredContent` plus complete compact `content`; summary-only text is gated on host-forwarding evidence ([#191](https://github.com/zackbart/connecta/issues/191)) |
84
86
  | Code mode (`execute_code`) | accepted | the primary read, discovery, and composition surface: smaller serialized definitions, far smaller results once composition and projection happen before the model sees them, and a cold-start model that read the interface without help ([exploration](./documentation/code-first-exploration.md), [#224](https://github.com/zackbart/connecta/issues/224)) |
85
- | Code-first as the default; the eval gate retired | accepted | owner decision, 2026-07-30: one operator, no deploy-time flip; [`eval/code-first-gate`](./eval/code-first-gate/README.md) survives as measurement, but nothing waits on its verdict ([#222](https://github.com/zackbart/connecta/issues/222), [#224](https://github.com/zackbart/connecta/issues/224)) |
87
+ | Code-first as the default; the eval gate retired | accepted | owner decision, 2026-07-30: one operator, no deploy-time flip; [`eval/code-first-gate`](https://github.com/zackbart/connecta/blob/main/eval/code-first-gate/README.md) survives as measurement, but nothing waits on its verdict ([#222](https://github.com/zackbart/connecta/issues/222), [#224](https://github.com/zackbart/connecta/issues/224)) |
86
88
  | Surface consolidation to seven tools | accepted | `list_connectors`, `describe_tools`, and `batch_call` fold into the program surface, deleting the routing choice between direct calls, batches, discovery, and execution; `call_tool` stays because a simple call is not cheaper through code ([#224](https://github.com/zackbart/connecta/issues/224)) |
87
89
  | Classic (executor-free) surface | removed | supersedes its provisional retention under [#224](https://github.com/zackbart/connecta/issues/224) — an executor is mandatory, and a deployment without one refuses to boot rather than serving a fallback shape ([#273](https://github.com/zackbart/connecta/issues/273)) |
88
90
  | Connector shortcut namespaces in programs | accepted | sugar over canonical addressing, kept but frozen — every expansion invents a collision class `<connectorId>.<toolName>` already solved ([#223](https://github.com/zackbart/connecta/issues/223)) |
@@ -132,8 +134,11 @@ Breaking one is not a bug fix — it is a design change wearing a disguise.
132
134
  `node:` builtin.
133
135
  - **The published surface is a boundary.** Heavyweight or platform-bound code
134
136
  goes behind an optional-peer subpath, never into core.
135
- - **No runtime admin.** If a browser could change what an agent can reach,
136
- that feature is a non-goal wearing a disguise.
137
+ - **Operator routes manage authentication material, never declared
138
+ capability.** Authenticating a declared capability is allowed; the connector
139
+ set, declared catalog and annotations, OAuth scopes, admission, authorization
140
+ rules, and caller tool scope take a config edit. A downstream catalog is
141
+ discovered, not declared — remote MCP tools appear when its credential does.
137
142
  - **Structural mistakes throw at construction.** A deployment that boots into
138
143
  the wrong shape is worse than one that refuses to boot.
139
144
 
@@ -8,7 +8,7 @@ and requires the Workers Paid plan.
8
8
  This is also the **starting template for a deployment**: a real deployment
9
9
  should be its own repository that pins an exact `@zackbart/connecta` version and
10
10
  owns only its connector configuration, auth policy, domain, bindings,
11
- migrations, and secrets. See [deployment architecture](../../documentation/operations.md).
11
+ migrations, and secrets. See [the Cloudflare guide](../../documentation/cloudflare.md).
12
12
 
13
13
  ## Files
14
14
 
@@ -41,6 +41,7 @@ wrangler secret put SUPPORT_TOKEN # one headless client
41
41
  wrangler secret put EXEC_TOKEN # another headless client
42
42
  wrangler secret put CLERK_SECRET_KEY
43
43
  wrangler secret put DOWNSTREAM_TOKEN
44
+ wrangler secret put CREDENTIAL_ENCRYPTION_KEY # base64 32-byte AES key
44
45
  wrangler deploy
45
46
  ```
46
47
 
@@ -49,9 +50,97 @@ Enable Dynamic Client Registration on the Clerk instance (OAuth Applications →
49
50
  DCR) so Claude/Cursor can self-register — full walkthrough in
50
51
  [setting up Clerk](../../documentation/auth.md).
51
52
 
53
+ ### Copied into its own repository
54
+
55
+ The `npm install` above is the connecta repository's, which already has every
56
+ dependency this file imports. A copy with its own `package.json` installs three
57
+ things, because two of them are not part of connecta and never install with it:
58
+
59
+ ```sh
60
+ npm install @zackbart/connecta @cloudflare/codemode @clerk/backend
61
+ ```
62
+
63
+ Both are optional peers of `@zackbart/connecta` — declared in its manifest,
64
+ never installed with it, and each carrying the range this release supports.
65
+ `@cloudflare/codemode` is the executor behind `execute_code`, published as
66
+ `^0.4.4 || ^0.5.0`: install a version inside that and npm stays quiet, install
67
+ one outside and npm says so at install time instead of leaving a Worker to
68
+ discover the skew in production ([#376](https://github.com/zackbart/connecta/issues/376)).
69
+
70
+ `@clerk/backend` is the peer behind `@zackbart/connecta/auth/clerk`, which
71
+ `src/index.ts` imports at the top level, so wrangler must resolve it at
72
+ build time. Miss it and the build stops at
73
+ `Could not resolve "@clerk/backend"`, which is a missing peer rather than a
74
+ broken example. Drop `clerkAuth` from `auth` if this deployment has no operator
75
+ sign-in, and the peer goes with it — but read
76
+ [the operator surface](#the-operator-surface) first, because a deployment
77
+ without it can never write a credential or issue an access token.
78
+
52
79
  Then point an MCP client at `<PUBLIC_URL>/mcp`, and open `<PUBLIC_URL>/` for
53
80
  Connections. Credentials is at `/credentials`, named MCP access tokens are at
54
- `/tokens`, Activity is at `/activity`, and legacy `/ui` redirects to `/`.
81
+ `/tokens`, Activity is at `/activity`, and legacy `/ui` redirects to `/`. Each
82
+ of those three appears in the nav only when this deployment can serve it — see
83
+ the next section for what turns each one on.
84
+
85
+ ## The operator surface
86
+
87
+ This example ships the whole operator feature set. Three quarters of it is on
88
+ as deployed; the fourth needs a database, so it is commented in place.
89
+
90
+ **Operator sign-in** is the `clerkAuth` entry in `src/index.ts`, alongside two
91
+ static bearers. The split is deliberate: a bearer is a client key that may call
92
+ tools and read connector status, while writing a credential or issuing an
93
+ access token requires an interactive Clerk identity. Narrow who that can be
94
+ with `allowedDomains`, or with a `gate` for anything a domain cannot express.
95
+
96
+ **The credential vault** is `credentials: { encryptionKey: … }`, backed by the
97
+ same KV namespace as everything else and encrypted with the
98
+ `CREDENTIAL_ENCRYPTION_KEY` secret before a value reaches it. Generate one with:
99
+
100
+ ```sh
101
+ node -e "console.log(crypto.randomBytes(32).toString('base64'))"
102
+ ```
103
+
104
+ Leave the secret unset and the deployment still runs — `/credentials` stays
105
+ read-only and connecta says so at startup. Keep the key in Worker secrets and
106
+ nowhere near KV: it is the only thing that makes a copied namespace useless.
107
+ Rotation takes effect on the next call, with no redeploy and no liveness probe,
108
+ because credentials fail at use.
109
+
110
+ The vault is ready here, and the Credentials page is still hidden, because that
111
+ page lists connector credential slots rather than deployments. Neither
112
+ connector in `src/index.ts` declares one — Notion carries a deployment-owned
113
+ static header and echo has no secret — so nothing would be on the page. Add
114
+ `credential: { label: "API token" }` to an `api()` connector (the commented
115
+ shape on `echo` is exactly it) or use a provider connector such as `notion()`,
116
+ which declares its own, and Credentials appears for a signed-in operator on the
117
+ next load.
118
+
119
+ **Access tokens** are `accessTokens: {}`. A signed-in operator mints named,
120
+ revocable Bearer tokens at `/tokens` for header-capable clients that will not do
121
+ OAuth. Secrets are shown once and only their hashes enter KV; a lost token is
122
+ reissued, never recovered. Note the KV caveat above — revocation is visible
123
+ everywhere only as fast as the namespace converges.
124
+
125
+ **Activity** is the commented block in `src/index.ts` and the commented
126
+ `d1_databases` binding in `wrangler.jsonc`; the section below creates the
127
+ database and applies the schema.
128
+
129
+ None of these change what agents can reach. Operator routes manage the
130
+ authentication material behind capabilities `src/index.ts` already declares —
131
+ never the connector set, the tool catalog, or its annotations.
132
+
133
+ `connecta doctor` reports the same line here as for a deployment with none of
134
+ this on: connector count, executor, seven tools. The executor it names is this
135
+ one — `DynamicWorkerExecutor executed`, not the Node template's QuickJS, which
136
+ is what doctor used to claim everywhere
137
+ ([#368](https://github.com/zackbart/connecta/issues/368)). It carries a bearer, and a
138
+ bearer learns the model-facing surface rather than the deployment's
139
+ configuration topology. Confirm the operator surface the way an operator will:
140
+ sign in at `<PUBLIC_URL>/` and check that Tokens is live. Credentials joins it
141
+ once a connector declares a `credential` slot, and Activity once the D1 wiring
142
+ below is on — the nav shows a page when the deployment can actually serve it,
143
+ so a missing page is the honest report that its half is still off.
55
144
 
56
145
  ## Code mode
57
146
 
@@ -64,20 +153,19 @@ The required Worker Loader binding is checked into `wrangler.jsonc`:
64
153
  ```
65
154
 
66
155
  `src/index.ts` constructs `DynamicWorkerExecutor` from `env.LOADER` and serves
67
- the seven-tool surface. A deployment copied into its own repository must also
68
- install the executor package:
69
-
70
- ```sh
71
- npm install @cloudflare/codemode
72
- ```
156
+ the seven-tool surface. The executor package is one of the installs a copied
157
+ deployment owns see
158
+ [copied into its own repository](#copied-into-its-own-repository).
73
159
 
74
160
  ## Activity history (optional)
75
161
 
76
162
  `src/d1-activity.ts` is a complete `ActivityStore` over D1 — keyset paging on
77
- `(occurred_at_ms, id)` plus a batched retention pass — but it is **not wired
78
- into `src/index.ts`**, so the example deploys without a database. To enable it:
163
+ `(occurred_at_ms, id)` plus a batched retention pass — but the wiring in
164
+ `src/index.ts` is **commented out**, so the example deploys without a database.
165
+ To enable it:
79
166
 
80
- 1. Create the database and bind it in `wrangler.jsonc`:
167
+ 1. Create the database and uncomment the `d1_databases` binding in
168
+ `wrangler.jsonc`, pasting in the id it prints:
81
169
 
82
170
  ```sh
83
171
  wrangler d1 create connecta-activity
@@ -137,7 +225,9 @@ into `src/index.ts`**, so the example deploys without a database. To enable it:
137
225
  the failure and returns the tool result unharmed — so the symptom is not an
138
226
  error your agent sees, it is an activity log that quietly stops recording.
139
227
 
140
- 3. Pass the store to `createConnecta`:
228
+ 3. In `src/index.ts`, uncomment the `d1ActivityStore` import, the `ACTIVITY_DB`
229
+ field on `Env`, and the `activity` block — the three commented fragments
230
+ that together read:
141
231
 
142
232
  ```ts
143
233
  import { d1ActivityStore } from "./d1-activity.js";
@@ -6,16 +6,25 @@
6
6
  * namespace. The required Worker Loader binding in wrangler.jsonc backs the
7
7
  * seven-tool surface.
8
8
  *
9
+ * The operator surface is wired here except for activity history, which needs
10
+ * a database this example does not create for you: sign-in, the credential
11
+ * vault, and access-token issuance are on, and activity is three commented
12
+ * lines below. README.md § "The operator surface" walks through all four.
13
+ *
9
14
  * Setup (this example has no package.json of its own — it self-references the
10
15
  * installed `@zackbart/connecta` package):
11
16
  * 1. `npm install` in the connecta package root (../../ from here) so the
12
- * package import and wrangler resolve.
17
+ * package import and wrangler resolve. A copy in its own repository
18
+ * installs `@zackbart/connecta @cloudflare/codemode @clerk/backend`
19
+ * instead — the last two are not part of connecta, and the Clerk import
20
+ * below is an optional peer wrangler resolves at build time.
13
21
  * 2. Create a KV namespace and put its id in wrangler.jsonc under `kv_namespaces`.
14
22
  * 3. Set secrets:
15
23
  * wrangler secret put SUPPORT_TOKEN
16
24
  * wrangler secret put EXEC_TOKEN
17
25
  * wrangler secret put CLERK_SECRET_KEY
18
26
  * wrangler secret put DOWNSTREAM_TOKEN
27
+ * wrangler secret put CREDENTIAL_ENCRYPTION_KEY
19
28
  * and CLERK_PUBLISHABLE_KEY + PUBLIC_URL as plain vars in wrangler.jsonc.
20
29
  * 4. Enable Dynamic Client Registration in the Clerk dashboard
21
30
  * (OAuth Applications -> DCR toggle) so Claude/Cursor can self-register.
@@ -32,6 +41,8 @@ import {
32
41
  } from "@zackbart/connecta";
33
42
  import { clerkAuth } from "@zackbart/connecta/auth/clerk";
34
43
  import { cloudflareKvStorage } from "./cloudflare-kv.js";
44
+ // Activity history, off by default because it needs a D1 database.
45
+ // import { d1ActivityStore } from "./d1-activity.js";
35
46
 
36
47
  interface Env {
37
48
  CONNECTA_KV: KVNamespace;
@@ -41,8 +52,16 @@ interface Env {
41
52
  EXEC_TOKEN: string;
42
53
  CLERK_PUBLISHABLE_KEY: string;
43
54
  CLERK_SECRET_KEY: string;
55
+ /**
56
+ * Base64 32-byte AES key encrypting operator-managed credentials in KV.
57
+ * Unset means no vault: /credentials stays read-only and connecta says so at
58
+ * startup. Never put it in KV — it is what protects KV.
59
+ */
60
+ CREDENTIAL_ENCRYPTION_KEY: string;
44
61
  DOWNSTREAM_TOKEN: string;
45
62
  PUBLIC_URL: string;
63
+ /** Uncomment with the `d1_databases` binding to enable activity history. */
64
+ // ACTIVITY_DB: D1Database;
46
65
  /**
47
66
  * Worker Loader binding (wrangler.jsonc `worker_loaders`) powering
48
67
  * execute_code. Dynamic Workers require the Workers Paid plan.
@@ -73,9 +92,30 @@ function build(env: Env) {
73
92
  // allowedDomains: ["acme.com"],
74
93
  }),
75
94
  ],
95
+ // Connectors that declare a `credential` slot become editable at
96
+ // /credentials, encrypted with this key before anything reaches KV. A
97
+ // saved replacement takes effect on the next call — no redeploy, and no
98
+ // liveness probe: credentials fail at use.
99
+ //
100
+ // The key is the vault, not the page: /credentials is a list of connector
101
+ // slots, so it stays hidden until a connector declares one. Neither
102
+ // connector below does — Notion here carries a deployment-owned static
103
+ // header and echo has no secret at all — so this example ships the vault
104
+ // ready and the page empty. Declare a slot (see the commented shape on
105
+ // `echo`, or use a provider connector like `notion()`, which declares its
106
+ // own) and the page appears on the next load.
107
+ credentials: { encryptionKey: env.CREDENTIAL_ENCRYPTION_KEY },
76
108
  // Eligible Clerk operators can create named, revocable MCP Bearer tokens
77
109
  // at /tokens. Secrets are shown once; only their hashes enter KV.
78
110
  accessTokens: {},
111
+ // Payload-free activity at /activity, off until a database exists to hold
112
+ // it. Uncomment the `d1_databases` binding in wrangler.jsonc, apply the
113
+ // schema in README.md § "Activity history", then these three lines and the
114
+ // import above.
115
+ // activity: {
116
+ // store: d1ActivityStore(env.ACTIVITY_DB),
117
+ // deploymentId: "production",
118
+ // },
79
119
  connectors: [
80
120
  remoteMcp("notion", {
81
121
  url: "https://mcp.notion.com/mcp",
@@ -87,6 +127,11 @@ function build(env: Env) {
87
127
  }),
88
128
  api("echo", {
89
129
  description: "Echo — text transforms",
130
+ // What a vault-backed connector adds — an operator edits this slot at
131
+ // /credentials and the handler reads it with
132
+ // `await ctx.credential?.get()`, so the secret never lives in source
133
+ // or in a Worker variable:
134
+ // credential: { label: "API token" },
90
135
  tools: [
91
136
  {
92
137
  name: "shout",
@@ -7,7 +7,8 @@
7
7
  "observability": { "enabled": true },
8
8
 
9
9
  // Plain vars. Secrets (SUPPORT_TOKEN, EXEC_TOKEN, CLERK_SECRET_KEY,
10
- // DOWNSTREAM_TOKEN) are set with `wrangler secret put <NAME>`, not here.
10
+ // CREDENTIAL_ENCRYPTION_KEY, DOWNSTREAM_TOKEN) are set with
11
+ // `wrangler secret put <NAME>`, not here.
11
12
  "vars": {
12
13
  "PUBLIC_URL": "https://connecta.example.workers.dev",
13
14
  "CLERK_PUBLISHABLE_KEY": "pk_test_replace-me"
@@ -18,6 +19,18 @@
18
19
  { "binding": "CONNECTA_KV", "id": "replace-with-kv-namespace-id" }
19
20
  ],
20
21
 
22
+ // Activity history. Create with `wrangler d1 create connecta-activity`,
23
+ // paste the id, apply the schema in README.md, then uncomment the matching
24
+ // lines in src/index.ts. Off by default so this example deploys without a
25
+ // database.
26
+ // "d1_databases": [
27
+ // {
28
+ // "binding": "ACTIVITY_DB",
29
+ // "database_name": "connecta-activity",
30
+ // "database_id": "replace-with-d1-database-id"
31
+ // }
32
+ // ],
33
+
21
34
  // Required by execute_code; Dynamic Workers use the Workers Paid plan.
22
35
  "worker_loaders": [{ "binding": "LOADER" }]
23
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zackbart/connecta",
3
- "version": "0.15.1",
3
+ "version": "0.16.1",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "One MCP to rule them all — a single MCP endpoint aggregating many downstream connectors behind a code-first surface of seven meta-tools.",
@@ -31,10 +31,7 @@
31
31
  "files": [
32
32
  "bin",
33
33
  "dist",
34
- "src",
35
- "assets",
36
34
  "documentation",
37
- "examples/node",
38
35
  "examples/worker",
39
36
  "templates",
40
37
  "AGENTS.md",
@@ -49,6 +46,7 @@
49
46
  "types": "./dist/index.d.ts",
50
47
  "import": "./dist/index.js"
51
48
  },
49
+ "./package.json": "./package.json",
52
50
  "./node": {
53
51
  "types": "./dist/node.d.ts",
54
52
  "import": "./dist/node.js"
@@ -100,10 +98,11 @@
100
98
  "check:docs": "node scripts/check-doc-links.mjs",
101
99
  "check:lint": "oxlint -D correctness --report-unused-disable-directives .",
102
100
  "check:unused": "knip --include dependencies,unlisted,exports,nsExports,types,nsTypes",
103
- "check:examples": "tsc -p tsconfig.examples.node.json && tsc -p tsconfig.examples.worker.json",
101
+ "check:examples": "tsc -p tsconfig.template.node.json && tsc -p tsconfig.examples.worker.json",
104
102
  "check:security": "npm audit --omit=dev --audit-level=moderate",
105
103
  "check:package": "node scripts/check-package.mjs",
106
104
  "load:admission": "npm run build && node scripts/admission-load.mjs",
105
+ "drift:check": "tsx scripts/drift-check.mjs",
107
106
  "check": "npm run check:docs && npm run check:operator-ui && npm run check:lint && npm run check:unused && npm run typecheck && npm run test && npm run build && npm run check:examples",
108
107
  "release:check": "npm run check && npm run check:security && npm run check:package",
109
108
  "prepack": "npm run check",
@@ -117,19 +116,23 @@
117
116
  },
118
117
  "peerDependencies": {
119
118
  "@clerk/backend": "^3.12.0",
119
+ "@cloudflare/codemode": "^0.4.4 || ^0.5.0",
120
120
  "quickjs-emscripten": "^0.32.0"
121
121
  },
122
122
  "peerDependenciesMeta": {
123
123
  "@clerk/backend": {
124
124
  "optional": true
125
125
  },
126
+ "@cloudflare/codemode": {
127
+ "optional": true
128
+ },
126
129
  "quickjs-emscripten": {
127
130
  "optional": true
128
131
  }
129
132
  },
130
133
  "devDependencies": {
131
134
  "@clerk/backend": "^3.12.0",
132
- "@cloudflare/codemode": "^0.4.4",
135
+ "@cloudflare/codemode": "^0.5.0",
133
136
  "@cloudflare/vitest-pool-workers": "^0.18.8",
134
137
  "@cloudflare/workers-types": "^4.20250101.0 || ^5.0.0",
135
138
  "@playwright/test": "^1.62.0",
@@ -137,6 +140,7 @@
137
140
  "esbuild": "^0.28.0",
138
141
  "knip": "^6.29.0",
139
142
  "oxlint": "^1.76.0",
143
+ "preact": "^10.29.8",
140
144
  "quickjs-emscripten": "^0.32.0",
141
145
  "tsx": "^4.23.1",
142
146
  "typescript": "^5.6.0",
@@ -0,0 +1,10 @@
1
+ # The image installs its own dependencies and never needs local state or
2
+ # secrets in the build context.
3
+ node_modules
4
+ .git
5
+ .env
6
+ .connecta-state.json
7
+ .connecta-activity.jsonl
8
+ *.log
9
+ Dockerfile
10
+ docker-compose.yml
@@ -1,5 +1,42 @@
1
- # Required. Use a long random value and keep it out of source control.
2
- CONNECTA_TOKEN=replace-me
1
+ # Required, and deliberately empty. Both Compose and src/index.ts refuse to
2
+ # start while it is, so a copied .env cannot become a running deployment on a
3
+ # placeholder printed in this template. Use a long random value and keep it out
4
+ # of source control:
5
+ # node -e "console.log(crypto.randomBytes(32).toString('base64url'))"
6
+ CONNECTA_TOKEN=
3
7
 
4
- # Optional. Defaults to 8787.
8
+ # Optional. Defaults to 8787. Compose publishes this port on the host too.
5
9
  PORT=8787
10
+
11
+ # Optional. The origin this deployment answers on, once it answers on more
12
+ # than this machine: downstream OAuth calls back to
13
+ # <PUBLIC_URL>/oauth/callback/<connectorId>. Defaults to http://localhost:<PORT>.
14
+ PUBLIC_URL=
15
+
16
+ # Optional. Where fileStorage keeps downstream-OAuth tokens and catalogs.
17
+ # Defaults to ./.connecta-state.json locally and /data/connecta-state.json in
18
+ # the container — keep the container path under /data so state lands on the
19
+ # named volume and survives a rebuild.
20
+ CONNECTA_STATE_FILE=
21
+
22
+ # --- Operator surface ---------------------------------------------------
23
+ # Each of these is read only once the matching block in src/index.ts is
24
+ # uncommented. Setting one on its own changes nothing.
25
+
26
+ # Operator sign-in with Clerk. Only a signed-in operator may write a credential
27
+ # or issue an access token; the bearer above is a client key, not an admin key.
28
+ # Also run `npm install @clerk/backend` — it is an optional peer.
29
+ CLERK_PUBLISHABLE_KEY=
30
+ CLERK_SECRET_KEY=
31
+
32
+ # Credential vault. Base64-encoded 32-byte AES key encrypting the values an
33
+ # operator saves at /credentials. Generate one with:
34
+ # node -e "console.log(crypto.randomBytes(32).toString('base64'))"
35
+ # Keep it here or in a secret store — never in the state file it protects, and
36
+ # never in source control. Losing it makes stored credentials unreadable.
37
+ CONNECTA_CREDENTIAL_KEY=
38
+
39
+ # Payload-free activity history. Defaults to ./.connecta-activity.jsonl locally
40
+ # and /data/connecta-activity.jsonl in the container — same reasoning as the
41
+ # state file: keep it under /data so history survives a rebuild.
42
+ CONNECTA_ACTIVITY_FILE=
@@ -6,13 +6,28 @@ This repository is deployment configuration, not a copy of Connecta itself.
6
6
  - Keep `executor: quickJsExecutor()` for the prescribed seven-tool code-first
7
7
  surface.
8
8
  - Keep credentials in environment variables or an external secret store.
9
- Never commit `.env`, `.connecta-state.json`, tokens, or credential values.
9
+ Never commit `.env`, `.connecta-state.json`, `.connecta-activity.jsonl`,
10
+ tokens, or credential values.
10
11
  - Add application logic only inside deliberate `api()` connector handlers.
11
12
  Do not copy or modify Connecta package internals here.
12
13
  - Prefer `api()` when the agent must see an exact reviewed capability surface;
13
14
  `remoteMcp()` follows the downstream server's evolving tool catalog.
15
+ - The operator surface — Clerk sign-in, credential vault, access tokens,
16
+ activity — ships as commented blocks in `src/index.ts`. Enable one by
17
+ uncommenting it and setting the variables it names in `.env`, never by
18
+ inventing a parallel configuration path. `README.md` § "Turn on the operator
19
+ surface" is the walkthrough; `src/file-activity.ts` is the deployment-owned
20
+ activity store the activity block wires.
14
21
  - Run `npm run typecheck` after configuration changes. With the server running,
15
22
  run `CONNECTA_TOKEN=... npm run doctor` before calling setup complete.
23
+ - `Dockerfile` and `docker-compose.yml` containerize *this* source; they are
24
+ the same deployment, not a second one. Configuration belongs in `.env` and
25
+ `src/index.ts`, never in a divergent container entrypoint.
26
+ - Moving this deployment to a newer Connecta is its own procedure, and it is
27
+ not a re-`init` — `connecta init` refuses to merge into an existing path on
28
+ purpose. Follow
29
+ [the upgrade guide](https://github.com/zackbart/connecta/blob/main/documentation/upgrading.md),
30
+ which also ships at `node_modules/@zackbart/connecta/documentation/upgrading.md`.
16
31
 
17
32
  Do not add alternate entrypoints, policy layers, generated connector catalogs,
18
33
  or runtime connector registration. Keep the deployment small enough to review
@@ -0,0 +1,49 @@
1
+ # This deployment, containerized. The build context is this directory: the
2
+ # image installs @zackbart/connecta from the registry exactly like any other
3
+ # consumer, so nothing here depends on the Connecta repository.
4
+ #
5
+ # docker compose up -d --build
6
+ FROM node:22-slim
7
+
8
+ WORKDIR /app
9
+
10
+ # `connecta init` deliberately leaves no lockfile — it rewrites the Connecta
11
+ # version pin, and a lockfile shipped in the template would already disagree
12
+ # with it. Without one the build resolves the pin itself, which is fine but not
13
+ # reproducible. Run `npm install` on the host and commit the `package-lock.json`
14
+ # it writes: the build context then carries it and every later build takes the
15
+ # `npm ci` path. A lockfile written inside this layer stays inside the image.
16
+ # Dev dependencies stay in: tsx runs src/index.ts directly, so the deployment
17
+ # you review is the deployment that runs.
18
+ COPY package.json package-lock.json* ./
19
+ RUN if [ -f package-lock.json ]; then \
20
+ npm ci --include=dev; \
21
+ else \
22
+ npm install --include=dev --no-audit --no-fund; \
23
+ fi
24
+
25
+ COPY tsconfig.json ./
26
+ COPY src ./src
27
+
28
+ # State lives on a mounted volume. The image owns the mount point so a fresh
29
+ # named volume inherits an owner the non-root user can actually write to.
30
+ RUN mkdir -p /data && chown -R node:node /data /app
31
+ USER node
32
+
33
+ ENV NODE_ENV=production
34
+ ENV PORT=8787
35
+ ENV CONNECTA_STATE_FILE=/data/connecta-state.json
36
+ # Read only once the activity block in src/index.ts is uncommented; defaulted
37
+ # here so history lands on the volume rather than inside the container layer.
38
+ ENV CONNECTA_ACTIVITY_FILE=/data/connecta-activity.jsonl
39
+ EXPOSE 8787
40
+
41
+ # /health is always open, so the probe never carries the bearer token and
42
+ # never leaves the container.
43
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
44
+ CMD node -e "fetch('http://127.0.0.1:'+(process.env.PORT||8787)+'/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
45
+
46
+ # `node --import tsx` keeps Node itself in the foreground: no wrapper process
47
+ # swallows SIGTERM, so `docker compose down` stops the server promptly and the
48
+ # QuickJS children go with it.
49
+ CMD ["node", "--import", "tsx", "src/index.ts"]