@creatornader/agent-bridge 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +150 -1
  2. package/README.md +239 -5
  3. package/ROADMAP.md +59 -7
  4. package/SECURITY.md +55 -5
  5. package/SKILL.md +103 -0
  6. package/dist/archive.d.ts +2 -2
  7. package/dist/archive.js +2 -2
  8. package/dist/{bridge-service-hX1ZQp4W.d.ts → bridge-service-YTjGr91A.d.ts} +1 -1
  9. package/dist/{bridge-store-DPVSCwfs.d.ts → bridge-store-Boaj-ZbO.d.ts} +2 -0
  10. package/dist/bridge.d.ts +17 -7
  11. package/dist/bridge.js +15 -7
  12. package/dist/{chunk-WAI2IYIQ.js → chunk-3YHVUPU2.js} +48 -5
  13. package/dist/chunk-3YHVUPU2.js.map +1 -0
  14. package/dist/{chunk-45BZGB77.js → chunk-6BTJE6D4.js} +168 -7
  15. package/dist/chunk-6BTJE6D4.js.map +1 -0
  16. package/dist/{chunk-5GMB3A77.js → chunk-DQOZJJZ2.js} +22 -10
  17. package/dist/chunk-DQOZJJZ2.js.map +1 -0
  18. package/dist/{chunk-NCO7RLBM.js → chunk-GTK4KOED.js} +108 -8
  19. package/dist/chunk-GTK4KOED.js.map +1 -0
  20. package/dist/{chunk-GADH244D.js → chunk-IHZFI7TH.js} +12 -4
  21. package/dist/chunk-IHZFI7TH.js.map +1 -0
  22. package/dist/{chunk-CEXBMOI5.js → chunk-LAHNQZDN.js} +2 -2
  23. package/dist/{chunk-UAHMP6GC.js → chunk-MCKKVNCE.js} +9 -6
  24. package/dist/chunk-MCKKVNCE.js.map +1 -0
  25. package/dist/{chunk-MBPZXTJA.js → chunk-PDIHDBP3.js} +173 -20
  26. package/dist/chunk-PDIHDBP3.js.map +1 -0
  27. package/dist/{chunk-Q6PPMXJC.js → chunk-SV3SVBYS.js} +377 -21
  28. package/dist/chunk-SV3SVBYS.js.map +1 -0
  29. package/dist/{chunk-SPSMZOCJ.js → chunk-SYGONYMM.js} +4 -4
  30. package/dist/{chunk-A6W4QALF.js → chunk-TC6A7GMF.js} +2 -2
  31. package/dist/cli.js +5865 -436
  32. package/dist/cli.js.map +1 -1
  33. package/dist/client-runtime.d.ts +4 -2
  34. package/dist/client-runtime.js +6 -6
  35. package/dist/contracts/generate.js +1 -1
  36. package/dist/dr.d.ts +9 -2
  37. package/dist/dr.js +6 -4
  38. package/dist/{gateway-CggQ8vTC.d.ts → gateway-BQHpV-MZ.d.ts} +27 -3
  39. package/dist/gateway-main.js +69 -5
  40. package/dist/gateway-main.js.map +1 -1
  41. package/dist/gateway.d.ts +3 -3
  42. package/dist/gateway.js +2 -2
  43. package/dist/index.js +7 -7
  44. package/dist/{postgres-bridge-store-Bfd3hRId.d.ts → postgres-bridge-store-WASumj26.d.ts} +1 -1
  45. package/dist/server.js +7 -7
  46. package/dist/sqlite-edge-store-Bc15DvpX.d.ts +148 -0
  47. package/dist/sqlite.d.ts +19 -80
  48. package/dist/sqlite.js +11 -3
  49. package/docs/architecture-v2.md +256 -10
  50. package/docs/decisions/0004-client-lifecycle-and-endpoint-migration.md +204 -0
  51. package/docs/deployment.md +205 -0
  52. package/docs/troubleshooting.md +23 -0
  53. package/llms.txt +67 -0
  54. package/openapi/agent-bridge-v2.openapi.json +1023 -0
  55. package/package.json +6 -2
  56. package/schemas/agent-bridge-v2.capabilities.json +24 -0
  57. package/schemas/agent-bridge-v2.mcp.json +6 -0
  58. package/schemas/agent-bridge-v2.schema.json +163 -0
  59. package/sql/migrations/017_gateway_authority_binding.sql +99 -0
  60. package/sql/migrations/018_endpoint_migration_challenges.sql +1028 -0
  61. package/sql/migrations/019_endpoint_migration_same_successor.sql +324 -0
  62. package/dist/chunk-45BZGB77.js.map +0 -1
  63. package/dist/chunk-5GMB3A77.js.map +0 -1
  64. package/dist/chunk-GADH244D.js.map +0 -1
  65. package/dist/chunk-MBPZXTJA.js.map +0 -1
  66. package/dist/chunk-NCO7RLBM.js.map +0 -1
  67. package/dist/chunk-Q6PPMXJC.js.map +0 -1
  68. package/dist/chunk-UAHMP6GC.js.map +0 -1
  69. package/dist/chunk-WAI2IYIQ.js.map +0 -1
  70. /package/dist/{chunk-CEXBMOI5.js.map → chunk-LAHNQZDN.js.map} +0 -0
  71. /package/dist/{chunk-SPSMZOCJ.js.map → chunk-SYGONYMM.js.map} +0 -0
  72. /package/dist/{chunk-A6W4QALF.js.map → chunk-TC6A7GMF.js.map} +0 -0
@@ -0,0 +1,204 @@
1
+ # ADR 0004: Client lifecycle ownership and endpoint migration
2
+
3
+ Status: accepted
4
+
5
+ Date: 2026-07-18
6
+
7
+ ## Context
8
+
9
+ Agent Bridge can install Codex, Claude Code, and Claude Desktop registrations, but an
10
+ existing registration may have been created by an older package or by an operator.
11
+ Repair, update, uninstall, and endpoint migration must not silently take ownership of
12
+ such state. In particular, host configuration and per-client backend files may contain
13
+ credential-bearing references and queued gateway edge state.
14
+
15
+ Lifecycle unit 1 needs a safe ownership boundary before later mutating operations are
16
+ added. It must distinguish missing state, exact but unowned state, owned state, and
17
+ drift without probing a gateway or exposing backend configuration values.
18
+
19
+ ## Decision
20
+
21
+ The CLI provides two local lifecycle operations for the three automated adapters:
22
+
23
+ - `clients inspect` is read-only. The operator supplies the expected runtime,
24
+ identity, stable instance key, backend file path, launch command, and Claude Code
25
+ scope when applicable. Inspection reads only the host registration, backend path
26
+ existence, and managed metadata. It does not read backend values, contact the
27
+ gateway, interpret connectivity health, rewrite a host config, or create metadata.
28
+ - `clients adopt` uses the same exact contract. Without `--apply` it returns a plan.
29
+ With `--apply` it may create managed metadata only when inspection reports an exact
30
+ unmanaged registration. Adoption never rewrites the registration or backend file.
31
+
32
+ Inspection returns one of four states:
33
+
34
+ - `absent`: the requested registration, backend file, and managed metadata are all absent.
35
+ - `unmanaged`: the host registration, identity, instance, backend path, scope, and
36
+ launch contract are exact, the backend path and its immediate parent pass the
37
+ no-link owner-only private-path policy, and metadata is absent.
38
+ - `managed`: the exact registration and backend file are accompanied by exact managed
39
+ metadata.
40
+ - `drifted`: any other combination, including malformed or inexact registration,
41
+ missing, insecure, or linked backend residue without a registration, stale metadata,
42
+ or metadata that structurally differs from the requested contract.
43
+
44
+ Managed metadata uses schema `agent-bridge.client-management`, version 1, under the
45
+ owner-only `~/.agent-bridge/clients/` directory. It records only runtime, identity,
46
+ instance, absolute backend path, launch command and arguments, scope, and a nonsecret
47
+ registration locator. Claude Desktop records the normalized configuration path.
48
+ Codex records the active profile configuration path. Claude Code records scope and,
49
+ for local or project scope, the normalized invocation directory. Its native CLI does
50
+ not expose a stronger configuration locator. User scope has no directory context. A
51
+ later inspection from a different locator reports drift instead of guessing which
52
+ registration to mutate. Metadata never copies a token, backend setting, credential
53
+ identifier, URL, workspace, or backend file contents. Publication uses a private
54
+ same-directory temporary file, file fsync, atomic rename, private-path verification,
55
+ and directory fsync where supported.
56
+
57
+ Codex inspection compares the semantic registration fields in its real JSON MCP
58
+ description and ignores status, timeout, and transport diagnostic fields. JSON object
59
+ property order is not significant, while the environment must contain exactly the
60
+ three Agent Bridge keys. Claude Code inspection uses its native MCP description and
61
+ exact scope/removal contract but excludes connectivity status from registration
62
+ exactness. Claude Desktop inspection reads only the `agent-bridge` entry in its JSON
63
+ configuration and uses the installer's canonical resolver: an explicit executable is
64
+ validated, while the default is absolute Node plus the absolute server entry.
65
+
66
+ Identity, instance, backend, and command inputs are normalized before comparison and
67
+ metadata publication. Desktop configuration and Codex profile paths are normalized
68
+ before they become locators. Claude Code local and project adoption must run from the
69
+ directory that later lifecycle operations should use. After publication, adoption
70
+ re-inspects the live registration and fails if it changed. Inspection and plan-only
71
+ adoption preserve backend bytes, inode, and modification time. Applied adoption
72
+ writes only the management metadata described above; registration state and client
73
+ health remain separate authorities.
74
+
75
+ First-time `clients install` and enrollment behavior remains unchanged. A provision
76
+ enrollment still refuses an existing backend file or MCP registration, so adoption
77
+ cannot weaken first-install collision protection.
78
+
79
+ `clients repair`, `clients update`, and `clients uninstall` operate only on a strict
80
+ managed metadata record.
81
+ The runtime and stable instance locate that record. `--identity` must match the record
82
+ and the immutable request, but never locates it. These commands reject
83
+ backend path, scope, and config-path flags.
84
+ They plan without writing by default. A no-op exact registration creates no operation.
85
+
86
+ Repair restores the recorded launch. Update resolves a replacement launch before it
87
+ creates a journal. The update request records the identity, command, arguments, scope,
88
+ and fixed three Agent Bridge environment key names. It does not record their values.
89
+ Native launch arguments are empty. A native command is one executable contract. Bare
90
+ commands reject argument separators and URL-like surfaces. Absolute paths must resolve
91
+ to executable files before an update is journaled. Claude Desktop uses the installer's
92
+ absolute launch resolver. An action-specific resume uses that recorded request and
93
+ rejects another action, runtime, instance, identity, or replacement command.
94
+
95
+ Before a mutation starts, metadata load verifies the private management root, clients
96
+ directory, and metadata file. It rejects links, replacement, oversized files, unknown
97
+ keys, incorrect schema versions, malformed locators, and non-absolute backend paths.
98
+ The file is opened without following links and checked against its path identity before
99
+ the loader accepts it. The full record is loaded again after the client lock is acquired
100
+ and before every non-metadata mutation. Any difference blocks the operation.
101
+
102
+ Repair can tighten backend privacy only when that change removes access. Its journal
103
+ proofs contain the role, file identity, and private or repairable policy state. They
104
+ never contain backend bytes, credentials, URLs, workspace, or configuration values.
105
+ Links, disappearance, owner changes, replacement, and a permission change that would
106
+ grant new owner access fail closed. Windows accepts an already private backend path and
107
+ refuses a non-private one because the repair path cannot prove a monotonic ACL change.
108
+
109
+ Registration proofing records a bounded Agent Bridge observation and its full target
110
+ contract. Unknown environment keys, malformed values, unexpected scope, opaque fields,
111
+ or arguments outside the stored current or target launch stop before journal creation.
112
+ For Codex, get, remove, and add run with the recorded `CODEX_HOME` over the supplied
113
+ environment. Claude Code uses the recorded scope, invocation directory, and supplied
114
+ environment. Native changes remove, verify absence, add, verify the target, and write
115
+ changed metadata last. Claude Desktop reads the recorded JSON config without following
116
+ links or link ancestors, changes only `mcpServers.agent-bridge`, and publishes through
117
+ a private operation-scoped temporary file. It pins and rechecks the original file and
118
+ parent identities before rename, then verifies the final entry. Claude Desktop has no
119
+ cooperative transaction protocol. Node cannot guarantee a transaction against an
120
+ independent same-user writer.
121
+
122
+ The operation substrate remains internal with read-only inspection. Revisioned
123
+ manifests contain typed credential-agnostic requests, non-sensitive locators, and
124
+ unique no-replace before/after artifacts. Begin holds the runtime-plus-instance lock
125
+ while refusing another unfinished operation; a blocked journal fences new mutations and
126
+ resume. Resume is same-host only. Journal states
127
+ are prepared, snapshotted, in-progress, applied, cleaning, and committed. Inspection
128
+ separately reports resumable, classification-required, blocked, or complete.
129
+
130
+ Repair and uninstall journals use operation format version 3. New update journals use
131
+ v4 and carry a bounded credential-free inverse contract. Gateway migration staging
132
+ uses v5 and binds a managed identity, source and target endpoint digests, enrollment
133
+ credential IDs, a source edge database path and scope key, and a predecessor grace
134
+ cutoff. It contains no raw gateway URL or token. A version 2 journal keeps its released
135
+ request shape and remains inspectable. A non-terminal version 2 journal cannot resume
136
+ because it lacks an identity-bound request.
137
+
138
+ Endpoint cutover uses v6. Its journal retains the normalized source gateway URL without
139
+ a token so post-journal recovery can reconstruct the source edge route from the target
140
+ successor backend. Initial preflight uses the predecessor and direct successor. Every
141
+ later proof and source-edge replay uses the successor credential at both URLs. There is
142
+ no endpoint reverse operation. Returning to a prior endpoint requires a fresh owner
143
+ rotation and a new forward cutover.
144
+
145
+ Creation pins the operation root before it publishes state. Cleanup pins that root,
146
+ the operation directory, and the snapshots directory before it records intent or
147
+ unlinks anything. Cleanup records durable intent per artifact, verifies and unlinks the pinned file, and
148
+ records POSIX directory sync or explicit Windows unavailability. An absent artifact is
149
+ safe only when intent predates the cleanup attempt. Inspection recognizes a verified
150
+ after artifact for the current intent-recorded step, but rejects other missing or extra
151
+ files. Committed means verified writes and removed artifacts. It drops requests, steps,
152
+ locators, digests, and artifact metadata while retaining a bounded credential-free
153
+ completion record for audit. Public repair, update, and uninstall use this substrate.
154
+
155
+ Uninstall is forward-only. It removes the managed registration and proves absence,
156
+ deletes the already private backend file, then deletes metadata. It refuses a backend
157
+ that still needs privacy repair, so it cannot loosen that policy as a side effect of
158
+ deletion. A later failure does not restore a registration, backend, or metadata file.
159
+ The uninstall plan never stores backend bytes. File deletion confirms the file and
160
+ private parent identities before unlink. POSIX syncs the parent directory after a
161
+ verified absence. Windows records unavailable directory durability. Node's pathname
162
+ unlink cannot provide a transaction against a same-user writer, so this is an advisory
163
+ race boundary. Desktop removes only `mcpServers.agent-bridge`.
164
+
165
+ `clients rollback <source-operation-id> --identity <name>` is plan-first and accepts
166
+ only a committed same-host v4 update source. `--apply` creates a new v4 `rollback`
167
+ operation. It verifies the asserted identity, prior nonsecret metadata and exact
168
+ registration contract, and the current forward metadata and registration digests.
169
+ Native rollback removes the forward registration, proves absence, adds the prior
170
+ registration, proves it, then writes prior metadata. Desktop replaces only
171
+ `mcpServers.agent-bridge` and writes prior metadata last. The source journal remains
172
+ unchanged. Reverse resume derives authority from its recorded source UUID and inverse
173
+ contract. A changed current state, v2 or v3 source, repair, uninstall, unsafe inverse
174
+ fields, or a different host fails closed. A failed forward update never rolls back
175
+ automatically. Repair remains monotonic. Uninstall recovery is re-enrollment.
176
+
177
+ `clients migrate stage <runtime> --identity <name> --instance <key>
178
+ --enrollment-file <path>` is plan-first. With `--apply`, it creates a private staged
179
+ successor backend and a credential-free v5 record without changing the managed
180
+ registration or active backend. It initializes the source edge gate and leaves its
181
+ state active. It probes active and staged bearer credentials and requires a
182
+ non-immediate predecessor grace cutoff. It neither drains the outbox nor authorizes a
183
+ cutover. It requires an absolute, normalized source edge database path and rejects
184
+ in-memory edge state. The stage does not prove that source and target URLs reach the
185
+ same database authority.
186
+
187
+ `clients resume <operation-id> [--recover-lock]` resumes v3 repair, update, and
188
+ uninstall requests, supported v4 update and rollback requests, and v5 migration-stage
189
+ requests. It derives action, runtime, instance, identity, launch, and reverse source
190
+ from the record and accepts no replacement client authority. It cannot resume a version
191
+ 2 operation. It also completes an uninstall interrupted after metadata deletion and a
192
+ rollback interrupted after any ordered step. A later endpoint cutover is limited to
193
+ alternate URLs and must dynamically attest one logical database authority. Physical
194
+ erasure is outside the contract.
195
+
196
+ ## Consequences
197
+
198
+ Managed repair, update, and uninstall have a narrow authority boundary and can fail
199
+ closed on drift, metadata corruption, ambiguous crash state, and unsafe backend policy
200
+ changes. Existing exact registrations still require intentional, reviewable adoption.
201
+ Migration staging preserves active state while it prepares later work. Endpoint
202
+ cutover uses a separate v6 journal to drain the gateway edge outbox, attest shared live
203
+ route state, change the host registration, and retain enough credential-free authority
204
+ for crash recovery and post-grace source retirement.
@@ -0,0 +1,205 @@
1
+ # Deploy Agent Bridge
2
+
3
+ The repository includes a Compose stack for local development and a production image
4
+ definition. The Compose file is intentionally bound to loopback. It is useful for
5
+ evaluation, integration work, and the repository acceptance test. It is not a public
6
+ TLS deployment.
7
+
8
+ ## Development stack
9
+
10
+ Requirements:
11
+
12
+ - Docker Engine or Docker Desktop with Compose v2.
13
+ - Node.js 22.23.1 or newer to generate private development secrets and run operator
14
+ commands from the source checkout.
15
+ - Free loopback ports 8787 and 54329, or explicit replacement values.
16
+
17
+ Create two independent passwords. Keep the files out of version control.
18
+
19
+ ```bash
20
+ mkdir -m 700 .secrets
21
+ node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('hex'))" > .secrets/postgres_password
22
+ node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('hex'))" > .secrets/runtime_password
23
+ chmod 600 .secrets/*
24
+ ```
25
+
26
+ Build and start the stack:
27
+
28
+ ```bash
29
+ docker compose build --pull gateway
30
+ docker compose up --wait gateway
31
+ curl --fail http://127.0.0.1:8787/readyz
32
+ ```
33
+
34
+ The services start in this order:
35
+
36
+ 1. PostgreSQL becomes healthy.
37
+ 2. `migrate` applies the ordered schema with the schema-owner login and exits.
38
+ 3. `bootstrap-runtime` creates or updates `agent_bridge_gateway`, grants the
39
+ database-derived runtime role, and exits.
40
+ 4. `gateway` starts with the restricted login and must pass `/readyz`.
41
+
42
+ The stack stores PostgreSQL data in the `postgres_data` named volume. `docker compose
43
+ down` removes containers and keeps the volume. `docker compose down --volumes` deletes
44
+ the development database. Inspect the project name and volume before using the second
45
+ command.
46
+
47
+ The default bindings are `127.0.0.1:8787` for the gateway and `127.0.0.1:54329` for
48
+ PostgreSQL. Override them without editing the file:
49
+
50
+ ```bash
51
+ AGENT_BRIDGE_PORT=18787 \
52
+ AGENT_BRIDGE_POSTGRES_PORT=15432 \
53
+ docker compose up --wait gateway
54
+ ```
55
+
56
+ Use the [owner enrollment workflow](../README.md#gateway-setup) to
57
+ create principal-bound credentials. Do not put a gateway token in the shared backend
58
+ config. Each installed client receives its own private backend file.
59
+
60
+ Run the same disposable proof as CI after building the TypeScript artifacts:
61
+
62
+ ```bash
63
+ npm ci
64
+ npm run build
65
+ ./scripts/compose-smoke.sh
66
+ ```
67
+
68
+ The script creates a unique Compose project name that callers cannot override. It also
69
+ creates temporary database passwords, a temporary operator, and two principal
70
+ credentials. It proves source and workspace binding, targeted delivery, lease
71
+ settlement, short-password rejection, denied runtime access to credential hashes, and
72
+ message persistence through a full stack restart with a fresh edge cache. Its exit trap
73
+ removes the project volume, image tag, credentials, and temporary files.
74
+
75
+ ## Production requirements
76
+
77
+ Use the image stages and service boundaries as inputs to the deployment platform. Do
78
+ not expose the checked-in Compose stack unchanged.
79
+
80
+ ### Network and TLS
81
+
82
+ - Keep PostgreSQL on a private network. Do not publish port 5432 to the internet.
83
+ - Put every non-loopback gateway behind a TLS terminator. Forward only from the trusted
84
+ proxy or ingress layer to the gateway's HTTP port.
85
+ - Restrict administrative database access to migration, owner-control, archive,
86
+ backup, and restore jobs. Clients use the HTTPS gateway, not PostgreSQL.
87
+ - Apply request size, connection, and upstream timeouts at the proxy without retrying
88
+ ambiguous mutations. Agent Bridge uses idempotency keys for safe publication replay.
89
+
90
+ ### Images and process policy
91
+
92
+ - Build from the pinned Node base image and deploy an immutable image digest.
93
+ - Run the gateway with a read-only root filesystem, a small writable temporary
94
+ filesystem, and `no-new-privileges`. The final gateway process must run as the
95
+ non-root image user with no effective Linux capabilities.
96
+ - Compose file secrets retain host ownership on native Linux. The migration and gateway
97
+ services therefore start a small Node entrypoint as root with `DAC_OVERRIDE`,
98
+ `SETUID`, and `SETGID`. It reads the one granted secret, drops supplementary groups
99
+ and UID/GID to 1000, then imports the requested module. The final process has no
100
+ effective capabilities. The one-shot runtime bootstrap keeps `DAC_OVERRIDE`,
101
+ `SETUID`, and `SETGID` while it reads the two secret files, then `gosu` runs its fixed
102
+ SQL script as the PostgreSQL account. A production
103
+ secret injector may mount the secret directly for the runtime UID and omit this
104
+ handoff.
105
+ - Allow at least 30 seconds for graceful shutdown. Stop accepting traffic before
106
+ terminating the process.
107
+ - Gate traffic on `/readyz`. Liveness alone does not prove migration, row-isolation,
108
+ role, or protected-catalog readiness.
109
+
110
+ ### Secrets and database roles
111
+
112
+ Keep these authorities separate:
113
+
114
+ | Authority | Purpose | Long-lived gateway access |
115
+ | --- | --- | --- |
116
+ | Schema owner | Ordered migrations and trusted role registration | Never |
117
+ | Runtime login | Gateway requests and readiness | Required |
118
+ | Control operator | Credential provision, inventory, rotation, and revocation | Never |
119
+ | Archive operator | Portable PostgreSQL archive operations | Never |
120
+ | Backup and restore | Native DR backup or restore | Never |
121
+
122
+ Use the platform's secret manager or private mounted secret files. Do not put raw
123
+ passwords, tokens, or complete database URLs in image layers, source control, command
124
+ arguments, deployment logs, or shared client config. Rotate each authority on its own
125
+ schedule and after any suspected exposure.
126
+
127
+ The runtime database password must contain at least 32 characters. The bootstrap job
128
+ fails before role creation or alteration when the mounted value is shorter.
129
+
130
+ ### Persistent data and backup
131
+
132
+ A database volume or managed PostgreSQL disk keeps runtime state. It does not protect
133
+ against operator error, catalog drift, account loss, or regional failure.
134
+
135
+ - Schedule native PostgreSQL DR backups with the exact PostgreSQL major tools.
136
+ - Store verified bundles on a separate failure domain.
137
+ - Record retention and deletion policy separately from message immutability.
138
+ - Run restore drills into a fresh database with the same name and PostgreSQL major.
139
+ - Never activate the source and restored target as authorities at the same time.
140
+
141
+ Portable archives complement native DR when an operator needs one workspace's messages
142
+ and eligible read receipts. They do not contain credentials, delivery state,
143
+ owner-control state, or security events.
144
+
145
+ ## Upgrade procedure
146
+
147
+ 1. Confirm the target image supports the deployed PostgreSQL major and current protocol
148
+ clients.
149
+ 2. Drain or preserve each gateway client's SQLite outbox. Do not discard an edge store
150
+ with queued publications.
151
+ 3. Drain old gateway instances or remove them from traffic before migration 017, then
152
+ keep them out of traffic before migration 018. An old process can serve ordinary
153
+ requests until it exits even though its `/readyz` probe
154
+ fails after the newer migration is applied.
155
+ 4. Create and verify a native DR backup.
156
+ 5. Stop schema-changing jobs other than the selected migration job.
157
+ 6. Run the new image's migration command once with schema-owner authority.
158
+ 7. Run the runtime bootstrap with separate runtime-login credentials.
159
+ 8. Start the new gateway and require `/readyz`, an authenticated capability probe, and
160
+ an authenticated status probe.
161
+ 9. Send, read, claim, and settle a disposable targeted delivery.
162
+ 10. Roll clients forward only after the gateway proof passes.
163
+ 11. Keep the previous authority available but inactive until the observation window
164
+ closes.
165
+
166
+ Run one migration job at a time. The migration ledger makes ordered application
167
+ idempotent, but it does not make concurrent deployment orchestration desirable.
168
+
169
+ ## Rollback boundaries
170
+
171
+ | Failure point | Safe response |
172
+ | --- | --- |
173
+ | Before schema migration | Stop the new gateway and return to the prior image and configuration. |
174
+ | After migration, before client rollout | Keep clients on the old authority. Apply a forward fix, or restore the verified backup into a fresh target. |
175
+ | After clients have published through the new gateway | Stop further cutover. Preserve every edge database and credential until queued outboxes are zero. Reconcile authoritative messages before switching back. |
176
+ | Database corruption or unrecoverable catalog drift | Restore native DR into a fresh target, verify readiness, then switch authority once. |
177
+
178
+ An older gateway may refuse a database with a newer migration plan. Starting the old
179
+ image is therefore not a general schema rollback. A volume snapshot is also not enough
180
+ unless its consistency and restore procedure have been proved for the database setup.
181
+ Migration 017 makes this readiness failure explicit for an old compiled migration
182
+ plan. It does not terminate an already-running old gateway. Drain it before applying
183
+ the migration.
184
+
185
+ ## Operational checks
186
+
187
+ - `/healthz` proves the HTTP process is alive.
188
+ - `/readyz` proves the gateway can use the restricted database and that required
189
+ security attestations still match.
190
+ - `agent-bridge doctor --json` probes a configured client's remote path.
191
+ - `agent-bridge status` is passive and reports remote reachability as unknown until a
192
+ probe occurs.
193
+ - Gateway metrics require a credential with `gateway:metrics`.
194
+
195
+ Alert on readiness failure, repeated authorization denial, rate-limit pressure,
196
+ database connection exhaustion, due or blocked outbox rows, dead-letter growth, backup
197
+ failure, and restore-test failure. Keep tokens, database URLs, message content, and DR
198
+ bundle paths out of telemetry.
199
+
200
+ Related references:
201
+
202
+ - [Architecture](architecture-v2.md)
203
+ - [Security policy](../SECURITY.md)
204
+ - [Troubleshooting](troubleshooting.md)
205
+ - [Portable archives and native DR](../README.md#portable-archives)
@@ -81,6 +81,29 @@ Queued sends retain their idempotency keys. Long-lived MCP clients retry them, a
81
81
  `agent-bridge sync` triggers the same bounded replay manually. Claims, lease changes,
82
82
  delivery settlement, presence, and read-receipt writes still require the gateway.
83
83
 
84
+ ## Migration gate reported by status or doctor
85
+
86
+ `clients migrate stage` does not begin a drain. `clients migrate cutover
87
+ <stage-operation-id> --exclusive-edge --apply` changes the source edge to `draining`
88
+ after it verifies both live gateways and their route challenge. In that state, normal
89
+ publication is blocked while the recorded lease worker completes existing outbox work.
90
+ `doctor` reports `draining` as degraded. A `retired` scope rejects new publication and
91
+ `doctor` reports it as failed.
92
+
93
+ Do not delete the edge database, alter the gate tables, or reopen a retired scope by
94
+ hand. Inspect the operation ID reported by status. Resume the matching v6 operation
95
+ with `clients resume <operation-id> [--recover-lock]`. A new worker cannot take an
96
+ unexpired drain lease. It must wait for the lease to expire. Reverse before the
97
+ predecessor grace cutoff is not supported. To return to the earlier endpoint, first
98
+ rotate a new owner credential for that endpoint, then run an ordinary forward cutover
99
+ with it as the successor. Finalization after grace retires the source. If no matching
100
+ operation exists, preserve the database and stop rather than changing the gate
101
+ manually.
102
+
103
+ A dry migration plan refuses an edge with live `-wal` or `-shm` sidecars. Stop the
104
+ writer and let SQLite checkpoint its state, then retry the plan. The plan never opens
105
+ the edge in write mode to inspect it.
106
+
84
107
  ## Report a defect
85
108
 
86
109
  Include the client name, operating system, package version, sanitized `doctor --json`
package/llms.txt CHANGED
@@ -11,6 +11,10 @@ History uses mailbox `inbox` (default), `sent`, or `all`. Receipt state is `any`
11
11
  - `npm install --global @creatornader/agent-bridge`
12
12
  - `agent-bridge init --provider local`
13
13
  - `agent-bridge demo`
14
+ - Development gateway: create `.secrets/postgres_password` and
15
+ `.secrets/runtime_password`, then run `docker compose up --build --wait gateway`.
16
+ Both checked-in port bindings are loopback-only. See `docs/deployment.md` before a
17
+ non-loopback deployment.
14
18
 
15
19
  If an MCP client cannot attach, run `agent-bridge doctor --json` and see
16
20
  `docs/troubleshooting.md`. Normal client installation resolves the MCP launch command;
@@ -30,6 +34,7 @@ services can call the CLI or HTTPS API or embed the Node library without a host
30
34
  ## Commands
31
35
 
32
36
  - `agent-bridge --version` or `agent-bridge -V`: print the installed package version without loading backend configuration.
37
+ - `agent-bridge --help`, `agent-bridge -h`, or a command followed by either help flag: print help without loading backend configuration or dispatching the command.
33
38
  - `agent-bridge capabilities`: print the canonical v2 operation and protocol capability document.
34
39
 
35
40
  - agent-bridge init --provider local
@@ -41,11 +46,49 @@ services can call the CLI or HTTPS API or embed the Node library without a host
41
46
  - agent-bridge claim, extend, ack, nack, deliveries, delivery-events, cancel, requeue
42
47
  - agent-bridge sync, watch, join, presence
43
48
  - agent-bridge clients install <runtime> --identity <principal>
49
+ - agent-bridge clients inspect <runtime> --identity <principal> --instance <stable-key> --backend-config <absolute path>
50
+ - agent-bridge clients adopt <runtime> --identity <principal> --instance <stable-key> --backend-config <absolute path> [--apply]
51
+ - agent-bridge clients repair <runtime> --identity <principal> --instance <stable-key> [--apply] [--resume <uuid>] [--recover-lock]
52
+ - agent-bridge clients update <runtime> --identity <principal> --instance <stable-key> [--command <command>] [--apply] [--resume <uuid>] [--recover-lock]
53
+ - agent-bridge clients uninstall <runtime> --identity <principal> --instance <stable-key> [--apply] [--resume <uuid>] [--recover-lock]
54
+ - agent-bridge clients rollback <update-operation-id> --identity <principal> [--apply] [--recover-lock]
55
+ - agent-bridge clients migrate stage <runtime> --identity <principal> --instance <stable-key> --enrollment-file <private-path> [--apply] [--recover-lock]
56
+ - agent-bridge clients migrate cutover <stage-operation-id> --exclusive-edge [--apply] [--recover-lock]
57
+ - agent-bridge clients migrate finalize <cutover-operation-id> --exclusive-edge [--apply] [--recover-lock]
58
+ - agent-bridge clients resume <operation-id> [--recover-lock] # resumes recorded v3, supported v4, v5 stage, or v6 migration authority
59
+ - agent-bridge clients operations [<operation-id>] # read-only resumable/classification-required/blocked/complete summaries
44
60
  - agent-bridge owner provision|inventory|rotate|revoke
45
61
  - agent-bridge clients install <runtime> --enrollment-file <private path>
46
62
  - agent-bridge archive export|verify|import
47
63
  - agent-bridge dr backup|verify|restore
48
64
 
65
+ Client inspection is local, read-only, secret-free, and reports absent, unmanaged,
66
+ managed, or drifted. Adoption is a plan unless `--apply` is explicit. It writes only
67
+ owner-private credential-free management metadata after the identity, stable instance,
68
+ backend path, scope, and launch contract match exactly; it never rewrites the host
69
+ registration or backend file. Enrollment-based first-time provisioning continues to
70
+ refuse registration and backend-file collisions. Metadata binds Desktop to its
71
+ normalized config path and Codex to its active profile config. Claude Code local and
72
+ project scope bind to the invocation directory because its native CLI exposes no
73
+ stronger registration target.
74
+ The backend and its immediate parent must pass the owner-only no-link policy. Codex
75
+ registration comparison ignores diagnostic fields and JSON property order but requires
76
+ exactly AGENT_BRIDGE_AGENT, AGENT_BRIDGE_INSTANCE, and AGENT_BRIDGE_CONFIG. Claude Code
77
+ connectivity status is not registration state. Desktop inspection uses the installer's
78
+ validated absolute launch resolver, and applied adoption re-inspects its postcondition.
79
+ Only Claude Code accepts `--scope`; only Claude Desktop accepts `--config-path` for
80
+ inspect and adopt. Repair, update, and uninstall derive those locators from strict managed metadata.
81
+ They reject backend, scope, and config-path authority flags. `--identity` binds the
82
+ metadata record and immutable request. Repair restores the recorded launch contract.
83
+ Update records a normalized credential-free launch request, including only fixed Agent
84
+ Bridge environment key names. Native commands are one executable contract and reject
85
+ arguments, URL-like selectors, and credential surfaces. Plan-only calls create no lock
86
+ or operation. Native changes prove remove then add. Desktop replaces only the Agent
87
+ Bridge config entry through a private operation-scoped temporary file. Its same-user
88
+ writer race is advisory because Node cannot provide an OS transaction. Resume requires
89
+ the same action and managed identity. Lock recovery requires
90
+ same-host process-death proof.
91
+
49
92
  Archive export moves one workspace's immutable messages and read receipts between
50
93
  canonical local SQLite and PostgreSQL stores. Import defaults to a rollback-backed dry
51
94
  run and requires `--apply` to commit. PostgreSQL archive authority comes only from
@@ -75,11 +118,16 @@ excludes transient request, rate-limit, instance, and archive-authorization rows
75
118
  normalizes claimed deliveries on restore. Never run source and restored target at the
76
119
  same time. The package API is @creatornader/agent-bridge/dr. Bundle hashes detect
77
120
  changed bytes but do not encrypt or authenticate the source.
121
+ The immutable PostgreSQL gateway authority UUID is preserved by native DR. It identifies
122
+ one logical authority across restore but does not fence a live clone.
78
123
 
79
124
  ## MCP tools
80
125
 
81
126
  - `capabilities`: return operations, required scopes, provider-specific enforcement, and supported protocol versions. Gateway access needs an active credential but no named scope for this operation.
82
127
  - Production gateway capabilities report `requestAuthority: true` and `rowIsolation: true` only after the migration and live catalog, role, policy, privilege, and function checks pass. PostgreSQL forces RLS on messages, receipts, deliveries, delivery events, and presence. Lease transitions and target-to-delivery membership remain service-enforced.
128
+ - Authenticated gateway `/v2/status` returns optional `gatewayAuthorityId` and
129
+ `credentialId` fields when PostgreSQL request authority is active. They are additive
130
+ in HTTP 2.1 and do not appear in capabilities.
83
131
 
84
132
  Compatibility: post_context, get_context, ack_context.
85
133
  Reliable messaging: send, history, claim, extend, acknowledge, negative_acknowledge, heartbeat, presence, sync.
@@ -122,6 +170,24 @@ workspace, and live MCP registration matches. Consumed-file deletion and lock re
122
170
  report retained, missing, durable, and durability-unknown outcomes without claiming that
123
171
  an unlinked path was retained.
124
172
 
173
+ `clients migrate stage` is a plan-first gateway migration preparation command. An
174
+ applied stage creates an owner-private successor backend and credential-free operation
175
+ record. It leaves the active registration, active backend, and source edge scope
176
+ active after initializing its gate. Staging requires an absolute, normalized source
177
+ edge database path and rejects `:memory:`.
178
+
179
+ `clients migrate cutover` requires a committed v5 stage and `--exclusive-edge`. Initial
180
+ preflight checks exact HTTP 2.1 status bindings at both gateways, one immutable
181
+ authority ID, the successor's `status:read` and `messages:write` grants, and a direct
182
+ predecessor-to-successor route challenge. Once it creates the journal, it uses a
183
+ retained normalized source URL and the successor credential for every route proof and
184
+ source outbox replay through the target gateway. `finalize` requires a fresh assertion
185
+ after grace expires and retires the source. To return to a former endpoint, rotate a
186
+ new owner credential and run an ordinary forward cutover to that endpoint. Dry runs
187
+ read private edge state without SQLite writes or gateway requests. They refuse live WAL
188
+ sidecars rather than read uncheckpointed outbox state. Resume uses only the retained v6
189
+ request and waits for an unexpired drain lease instead of taking it over.
190
+
125
191
  Project is an optional immutable message label, not a tenant or identity selector. Omitted project reads include labeled and unlabeled messages. Exact project filters are supported by CLI, MCP, HTTP, and stores. Gateway workspace assertions must match the bound credential before network access.
126
192
  Local CLI calls may override workspace for one invocation. The legacy Supabase schema is global and always reports workspace `*`; use project labels for legacy filtering.
127
193
 
@@ -132,6 +198,7 @@ Local CLI calls may override workspace for one invocation. The legacy Supabase s
132
198
  - SECURITY.md: reporting process and security boundaries
133
199
  - docs/ecosystem.md: relationship to adjacent protocols, brokers, and runtimes
134
200
  - docs/troubleshooting.md: MCP startup and client recovery
201
+ - docs/deployment.md: Compose development stack and production deployment constraints
135
202
  - docs/decisions/0001-protocol-layers-and-acknowledgment-semantics.md: protocol layers and acknowledgment semantics
136
203
  - docs/decisions/0002-canonical-operation-contract-registry.md: generated contracts and version negotiation
137
204
  - docs/decisions/0003-host-adapters-and-consumer-instance-keys.md: host layers and instance-key semantics