@creatornader/agent-bridge 0.3.0 → 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 (75) hide show
  1. package/CHANGELOG.md +174 -5
  2. package/README.md +341 -33
  3. package/ROADMAP.md +78 -16
  4. package/SECURITY.md +68 -1
  5. package/SKILL.md +104 -1
  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 +5856 -413
  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 +278 -13
  50. package/docs/decisions/0001-protocol-layers-and-acknowledgment-semantics.md +2 -2
  51. package/docs/decisions/0003-host-adapters-and-consumer-instance-keys.md +88 -0
  52. package/docs/decisions/0004-client-lifecycle-and-endpoint-migration.md +204 -0
  53. package/docs/deployment.md +205 -0
  54. package/docs/ecosystem.md +35 -3
  55. package/docs/troubleshooting.md +23 -0
  56. package/llms.txt +79 -3
  57. package/openapi/agent-bridge-v2.openapi.json +1023 -0
  58. package/package.json +6 -2
  59. package/schemas/agent-bridge-v2.capabilities.json +24 -0
  60. package/schemas/agent-bridge-v2.mcp.json +6 -0
  61. package/schemas/agent-bridge-v2.schema.json +163 -0
  62. package/sql/migrations/017_gateway_authority_binding.sql +99 -0
  63. package/sql/migrations/018_endpoint_migration_challenges.sql +1028 -0
  64. package/sql/migrations/019_endpoint_migration_same_successor.sql +324 -0
  65. package/dist/chunk-45BZGB77.js.map +0 -1
  66. package/dist/chunk-5GMB3A77.js.map +0 -1
  67. package/dist/chunk-GADH244D.js.map +0 -1
  68. package/dist/chunk-MBPZXTJA.js.map +0 -1
  69. package/dist/chunk-NCO7RLBM.js.map +0 -1
  70. package/dist/chunk-Q6PPMXJC.js.map +0 -1
  71. package/dist/chunk-UAHMP6GC.js.map +0 -1
  72. package/dist/chunk-WAI2IYIQ.js.map +0 -1
  73. /package/dist/{chunk-CEXBMOI5.js.map → chunk-LAHNQZDN.js.map} +0 -0
  74. /package/dist/{chunk-SPSMZOCJ.js.map → chunk-SYGONYMM.js.map} +0 -0
  75. /package/dist/{chunk-A6W4QALF.js.map → chunk-TC6A7GMF.js.map} +0 -0
package/README.md CHANGED
@@ -43,6 +43,26 @@ Restart the client, then run `agent-bridge doctor --json` if the MCP server does
43
43
  attach. The [troubleshooting guide](docs/troubleshooting.md) covers executable paths,
44
44
  client configuration, and recovery steps.
45
45
 
46
+ ## Run the gateway with Compose
47
+
48
+ The repository includes a loopback-only Compose stack for development and evaluation.
49
+ It starts PostgreSQL 16, runs the ordered migrations, creates a restricted runtime
50
+ login, and starts the authenticated gateway.
51
+
52
+ ```bash
53
+ mkdir -m 700 .secrets
54
+ node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('hex'))" > .secrets/postgres_password
55
+ node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('hex'))" > .secrets/runtime_password
56
+ chmod 600 .secrets/*
57
+ docker compose up --build --wait gateway
58
+ curl --fail http://127.0.0.1:8787/readyz
59
+ ```
60
+
61
+ The checked-in stack publishes the gateway and PostgreSQL only on loopback. It is not
62
+ a production TLS deployment. Read [the deployment guide](docs/deployment.md) before
63
+ exposing a gateway, changing network bindings, upgrading the schema, or relying on the
64
+ named volume for persistent data.
65
+
46
66
  ## What v2 provides
47
67
 
48
68
  - Immutable messages with UUIDv7 IDs and opaque server cursors.
@@ -54,8 +74,9 @@ client configuration, and recovery steps.
54
74
  - Idempotency conflict detection. Exact replay deduplicates; changed content under the same key fails.
55
75
  - Scoped credentials that bind a remote workspace and agent principal.
56
76
  - SQLite outbox and inbox cache for gateway clients.
57
- - Leased runtime presence with instance IDs and capabilities.
58
- - MCP, CLI, Codex, Claude Code, and Claude Desktop integration paths.
77
+ - Leased instance-keyed presence with capabilities.
78
+ - MCP, CLI, HTTPS, and Node library access, plus host adapters for Codex, Claude Code,
79
+ Claude Desktop, OpenClaw, and generic MCP clients.
59
80
  - Canonical portable archives for messages and read receipts across local SQLite and shared PostgreSQL stores.
60
81
  - Native SQLite and PostgreSQL backup, verification, and restore.
61
82
  - Existing `post_context`, `get_context`, `ack_context`, `post`, and `get` behavior during migration.
@@ -66,34 +87,81 @@ The canonical v2 operation registry generates [JSON Schema](schemas/agent-bridge
66
87
 
67
88
  Protocol 2.1 uses a gateway-first rollout. An upgraded gateway continues to serve released 2.0 clients, including headerless requests and their direct or null delivery results. A 2.1 client probes before mutation and proceeds only when complete, consistent response headers select 2.1 and advertise 2.1 support. It rejects mutation against a headerless or 2.0 gateway instead of downgrading. Upgrade the gateway before installing or starting 2.1 clients.
68
89
 
90
+ Two gateway-only HTTP 2.1 operations establish a short-lived endpoint-migration challenge. Initial preflight uses a direct predecessor and successor. After a cutover journal exists, the same active successor credential can issue at the retained source URL and consume at the target URL. Both calls require active transaction-bound authority and use the canonical credential and operation rate buckets. PostgreSQL stores only a domain-separated SHA-256 commitment. A challenge expires within 60 seconds and does not authorize endpoint cutover. Authenticated HTTP 2.1 capabilities include the credential's `grantedScopes`.
91
+
69
92
  The OpenAPI paths describe protocol 2.1. The embedded `x-agent-bridge-protocol-2.0` and `x-agent-bridge-schemas-2.0` vendor extensions contain frozen compatibility schema metadata for released 2.0 clients. They are not a second OpenAPI description. Gateway credentials enforce the operation scopes declared by the canonical registry. Local mode uses process identity, and legacy mode uses its configured key. Provider-neutral artifacts report this difference instead of claiming one authorization model for every backend.
70
93
 
71
94
  ## Architecture
72
95
 
73
- ```text
74
- Codex Claude Code Claude Desktop scripts
75
- | | | |
76
- +--------------+------------------+-----------------+
77
- MCP or CLI
78
- |
79
- process-scoped agent identity
80
- |
81
- +----------------+----------------+
82
- | |
83
- local SQLite SQLite edge store
84
- |
85
- authenticated HTTPS
86
- |
87
- Agent Bridge gateway
88
- |
89
- PostgreSQL
96
+ ```mermaid
97
+ flowchart TB
98
+ subgraph execution["Agent execution"]
99
+ harnesses["Agent harnesses<br/>product-specific or custom"]
100
+ callers["Non-harness callers<br/>scripts, CI jobs, and application services"]
101
+ end
102
+
103
+ subgraph hosts["Host surfaces"]
104
+ clis["Command-line hosts<br/>Codex CLI and Claude Code CLI"]
105
+ desktops["Desktop hosts<br/>Codex in ChatGPT and Claude Desktop"]
106
+ daemons["Daemons and custom MCP hosts"]
107
+ end
108
+
109
+ subgraph access["Integration and access"]
110
+ adapter["Host adapter or MCP registration"]
111
+ mcp["MCP over stdio: agent-bridge-mcp"]
112
+ cli["CLI: agent-bridge"]
113
+ library["Node library"]
114
+ direct["Direct HTTPS client"]
115
+ end
116
+
117
+ harnesses --> clis
118
+ harnesses --> desktops
119
+ harnesses --> daemons
120
+ clis --> adapter
121
+ desktops --> adapter
122
+ daemons --> adapter
123
+ adapter --> mcp
124
+ callers --> cli
125
+ callers --> library
126
+ callers --> direct
127
+
128
+ mcp --> core["Agent Bridge client core<br/>principal plus optional consumer instance key"]
129
+ cli --> core
130
+ library --> core
131
+
132
+ core --> local["Local mode<br/>SQLite authority"]
133
+ core --> edge["Gateway client mode<br/>SQLite edge outbox and cache"]
134
+ edge -->|"HTTPS protocol 2.1"| gateway["Agent Bridge gateway"]
135
+ direct -->|"HTTPS protocol 2.1"| gateway
136
+ gateway --> postgres["PostgreSQL authority"]
90
137
  ```
91
138
 
139
+ The diagram shows concepts, not exclusive product categories. A product may package a
140
+ harness and a host together. A harness is the agent execution environment. A host is
141
+ the CLI, desktop app, or daemon where it runs. A host adapter registers an access
142
+ surface. Scripts are orthogonal callers: they can invoke the CLI, call HTTPS, or embed
143
+ the Node library without becoming agent harnesses.
144
+
145
+ | Adapter or integration | Host coverage | Access | Installation status |
146
+ | --- | --- | --- | --- |
147
+ | `codex` | Codex CLI and Codex in the ChatGPT desktop app through their shared profile | MCP stdio | Automated |
148
+ | `claude-code` | Claude Code terminal harness | MCP stdio | Automated |
149
+ | `claude-desktop` | Claude Desktop application | MCP stdio | Automated |
150
+ | `openclaw` | OpenClaw host or daemon | MCP stdio | Manifest included; operator-managed |
151
+ | `generic-mcp` | Any compatible stdio MCP host | MCP stdio | Manifest included; operator-managed |
152
+ | Scripts and services | Shell jobs, CI, daemons, and application code | CLI, HTTPS, or Node library | Direct integration |
153
+ | Hermes, Pi, and other harnesses | Depends on the host's supported interface | No interface assumed | No dedicated adapter or conformance claim yet |
154
+
155
+ `agent-bridge-mcp` is a stdio server. The gateway exposes the Agent Bridge HTTPS API;
156
+ it is not MCP over HTTP. A direct HTTPS client can bypass MCP, the CLI, and the local
157
+ edge store, but then owns its own retry and offline behavior.
158
+
92
159
  Realtime notifications or hooks may wake a client, but cursored reads remain authoritative. A missed notification does not lose a message.
93
160
 
94
- A2A and application task semantics sit above Agent Bridge. MCP, CLI, and HTTPS are access surfaces. Optional transports such as SLIM or NATS may provide wakeups or transport below the core, but authoritative recovery still uses cursored pull. agmsg remains a reference for adapters, interoperability, and client experience.
161
+ A2A and application task semantics sit above Agent Bridge. MCP, CLI, HTTPS, and the Node library are access surfaces. Optional transports such as SLIM or NATS may provide wakeups or transport below the core, but authoritative recovery still uses cursored pull. agmsg remains a reference for adapters, interoperability, and client experience.
95
162
 
96
163
  [ADR-0001](docs/decisions/0001-protocol-layers-and-acknowledgment-semantics.md) defines this boundary and the distinct acknowledgment meanings.
164
+ [ADR-0003](docs/decisions/0003-host-adapters-and-consumer-instance-keys.md) defines the host layers and consumer instance-key contract.
97
165
 
98
166
  Agent Bridge is not a workflow engine, scheduler, memory system, terminal manager, or
99
167
  new universal agent protocol. See [Agent Bridge in the agent ecosystem](docs/ecosystem.md)
@@ -103,6 +171,8 @@ for its relationship to MCP, A2A, agmsg, brokers, and agent runtimes.
103
171
 
104
172
  - Node.js 22.23.1 or newer.
105
173
  - SQLite 3.51.3 or newer for local and edge storage. The supported Node version includes it.
174
+ - Concurrent local and edge initialization may wait up to 15 seconds for schema work;
175
+ normal database operations retain their configured busy timeout.
106
176
  - PostgreSQL 15, 16, 17, or 18 for gateway mode. New PostgreSQL majors fail the
107
177
  migration prerequisite and live readiness checks until their catalog digest is
108
178
  certified.
@@ -258,7 +328,8 @@ agent-bridge dr restore \
258
328
  PostgreSQL backup takes a repeatable-read snapshot while holding the native DR fence.
259
329
  It stores the `agent_bridge` schema dump plus a canonical inventory of required roles,
260
330
  memberships, and default privileges. The backup excludes transient data from agent
261
- instances, rate-limit buckets, request authority, and archive transaction authority.
331
+ instances, rate-limit buckets, request authority, endpoint-migration challenge rows, and
332
+ archive transaction authority.
262
333
  Restore turns claimed deliveries into immediately retryable work because a database
263
334
  restore cannot preserve a live lease.
264
335
 
@@ -308,9 +379,10 @@ directory durability proof. Successful Windows commands report
308
379
  library API is available from
309
380
  `@creatornader/agent-bridge/dr`.
310
381
 
311
- ## Install client integrations
382
+ ## Install host adapters
312
383
 
313
- Agent identity and gateway credentials belong to each client process, not the shared `~/.agent-bridge/config` file.
384
+ Agent identity and gateway credentials belong to each installed client, not the shared
385
+ `~/.agent-bridge/config` file.
314
386
 
315
387
  ```bash
316
388
  agent-bridge clients install codex --identity codex
@@ -330,11 +402,207 @@ AGENT_BRIDGE_CLIENT_TOKEN=<claude-desktop token> \
330
402
  agent-bridge clients install claude-desktop --identity claude-desktop
331
403
  ```
332
404
 
333
- `--token` accepts the same value, but the environment form avoids putting a credential in shell history. Each install writes an owner-only backend file under `~/.agent-bridge/clients/`. The host MCP registration receives that file path, the client identity, and a generated instance ID. Tokens are not copied into the shared config, and one client cannot reuse a token bound to another principal.
405
+ `--token` accepts the same value, but the environment form avoids putting a credential in shell history. Each install writes an owner-only backend file under `~/.agent-bridge/clients/`. The host MCP registration receives that file path, the client identity, and a generated stable instance key. Tokens are not copied into the shared config, and one client cannot reuse a token bound to another principal.
334
406
 
335
- Codex and Claude Code installation uses their native MCP commands. Claude Desktop installation merges the `agent-bridge` server into its JSON config with an atomic write. Restart the client after installation.
407
+ The `codex` adapter uses the Codex profile shared by the Codex CLI and the Codex
408
+ surface in the ChatGPT desktop app; it does not install two independent registrations.
409
+ Claude Code installation uses its native MCP command. Claude Desktop installation
410
+ merges the `agent-bridge` server into its JSON config with an atomic write. Restart the
411
+ client after installation.
336
412
 
337
- The runtime contracts are under [`clients/`](clients/). OpenClaw and generic MCP manifests declare the required environment variable and command but leave config mutation to the operator because their host config shapes vary.
413
+ Inspect an existing registration before making Agent Bridge its lifecycle owner:
414
+
415
+ ```bash
416
+ agent-bridge clients inspect codex --identity codex --instance <stable-key> \
417
+ --backend-config <absolute-client-backend-path>
418
+ agent-bridge clients adopt codex --identity codex --instance <stable-key> \
419
+ --backend-config <absolute-client-backend-path>
420
+ agent-bridge clients adopt codex --identity codex --instance <stable-key> \
421
+ --backend-config <absolute-client-backend-path> --apply
422
+ ```
423
+
424
+ `inspect` is local, read-only, and does not return backend values or credentials. It
425
+ classifies the requested registration as `absent`, `unmanaged`, `managed`, or
426
+ `drifted`. `adopt` is plan-only unless `--apply` is explicit, and application writes
427
+ only owner-private, credential-free management metadata after the identity, instance,
428
+ backend path, scope, launch contract, and registration locator match exactly. Adoption
429
+ never rewrites the host registration or backend file. Enrollment-based first-time
430
+ provisioning still refuses registration and backend-file collisions.
431
+ Claude Code inspection accepts the installed `--scope`; Claude Desktop accepts an
432
+ explicit validated `--command` and, when needed, `--config-path`; its default contract
433
+ is absolute Node plus the absolute server entry. Other adapters reject these
434
+ runtime-specific options. Managed metadata binds Desktop to that normalized config
435
+ path and Codex to its active profile config. Claude Code local and project adoption
436
+ bind to the current directory because the native CLI exposes no stronger locator, so
437
+ run those operations from the project context that later lifecycle commands should
438
+ use. Backend files and their immediate parents must satisfy the owner-only no-link
439
+ policy. Registration state is independent of connectivity health, and applied
440
+ adoption re-inspects before reporting success.
441
+
442
+ Once adopted, repair, update, and uninstall locate the registration from owner-private managed
443
+ metadata. The runtime and stable instance select that record. `--identity` must match
444
+ the recorded identity and the immutable request. These commands reject backend-path, scope, and host
445
+ config locator flags, so a caller cannot redirect a managed mutation.
446
+
447
+ ```bash
448
+ agent-bridge clients repair codex --identity codex --instance <stable-key>
449
+ agent-bridge clients repair codex --identity codex --instance <stable-key> --apply
450
+ agent-bridge clients update codex --identity codex --instance <stable-key> \
451
+ --command agent-bridge-mcp --apply
452
+ agent-bridge clients repair codex --identity codex --instance <stable-key> \
453
+ --apply --resume <operation-uuid>
454
+ agent-bridge clients uninstall codex --identity codex --instance <stable-key> --apply
455
+ agent-bridge clients rollback <update-operation-uuid> --identity codex
456
+ agent-bridge clients rollback <update-operation-uuid> --identity codex --apply
457
+ agent-bridge clients resume <operation-uuid>
458
+ agent-bridge clients migrate stage codex --identity codex --instance <stable-key> \\
459
+ --enrollment-file <private-path>
460
+ agent-bridge clients migrate cutover <stage-operation-uuid> --exclusive-edge
461
+ agent-bridge clients migrate cutover <stage-operation-uuid> --exclusive-edge --apply
462
+ agent-bridge clients migrate finalize <cutover-operation-uuid> --exclusive-edge --apply
463
+ ```
464
+
465
+ These commands return a plan by default. A managed registration that is already exact
466
+ and has a private backend file produces no operation. Repair restores the recorded
467
+ launch contract. Update validates and records a new credential-free launch contract
468
+ before it creates a journal. A native `--command` is one executable contract. Bare
469
+ commands cannot contain arguments or URL-like selectors. Absolute paths must resolve
470
+ to executable files. Native adapters remove, verify absence, add, and verify
471
+ the target registration. Claude Desktop replaces only `mcpServers.agent-bridge`,
472
+ preserves unrelated JSON values in memory, publishes through a private operation-scoped
473
+ temporary file, and verifies the new entry. Node cannot provide an OS transaction with
474
+ an uncooperative same-user Desktop writer. The pre-rename identity checks make this an
475
+ advisory race boundary rather than a guarantee.
476
+
477
+ Uninstall is forward-only. It removes the managed registration and verifies its
478
+ absence, deletes the private backend file, then deletes the management metadata. It
479
+ does not repair an unsafe backend before deletion. If the backend is not already
480
+ private, uninstall stops without changing the registration. It does not restore a
481
+ registration, backend, or metadata file after a later step fails. Desktop removes only
482
+ `mcpServers.agent-bridge` and preserves other JSON values. Backend and metadata removal
483
+ check the file and private parent identities before unlink. POSIX then syncs the parent
484
+ directory. Windows verifies the result but records unavailable directory durability.
485
+ Node cannot make pathname-based deletion atomic against an uncooperative same-user
486
+ writer, so that boundary remains advisory.
487
+
488
+ Rollback is explicit and update-only. A committed v4 update retains a bounded
489
+ credential-free inverse contract: its prior managed metadata, prior exact
490
+ registration contract, and digests for the forward metadata and registration state.
491
+ `clients rollback` uses only the source operation UUID and matching identity. It first
492
+ returns a plan. With `--apply`, it creates a separate reverse journal after it proves
493
+ the source is same-host, the source is a committed v4 update, and the current state
494
+ still matches the recorded forward state. Native reversal removes the forward entry,
495
+ adds the prior entry, then writes prior metadata. Claude Desktop replaces only its
496
+ Agent Bridge entry and writes prior metadata last. A reverse journal can resume with
497
+ `clients resume`; a second rollback fails because the forward state is no longer
498
+ present. Repair remains monotonic. Uninstall recovery requires re-enrollment.
499
+
500
+ `--resume` must name an unfinished operation for the same action, runtime, instance,
501
+ and identity. It uses the recorded request instead of new flags. `--recover-lock`
502
+ requires `--apply` and only removes an old same-host lock after the process-death
503
+ proof succeeds. Never delete a lock manually.
504
+
505
+ `clients resume <operation-uuid>` takes only recorded v3, supported v4, v5
506
+ migration-stage, or v6 endpoint-migration operation authority and an optional
507
+ `--recover-lock`. It does not accept a replacement action, runtime,
508
+ instance, identity, command, backend path, scope, or config locator. Use it for every
509
+ generic resume. It is also required when an uninstall has already deleted its final
510
+ metadata file, because the action-specific command has no metadata record left to
511
+ assert.
512
+
513
+ Repair and uninstall create v3 journals. New update and reverse rollback journals use
514
+ v4. Existing v2 journals remain inspectable. A non-terminal v2 journal lacks the
515
+ required identity-bound request, so it is blocked rather than resumed by these commands.
516
+
517
+ Managed-client operations now have a crash-safe local substrate under the owner-only
518
+ `~/.agent-bridge/operations/` directory. `agent-bridge clients operations` lists safe
519
+ operation summaries, and appending an operation UUID inspects one manifest. Output
520
+ never includes artifact contents or backend values. Update requests retain only a
521
+ normalized launch command, arguments, scope, and the fixed Agent Bridge environment
522
+ key names. Each immutable ordered plan names
523
+ registration, backend, and management-metadata targets with non-sensitive locators,
524
+ no-replace before and after artifacts, and expected digests. Registration artifacts
525
+ contain only bounded Agent Bridge fields and the full nonsecret target contract. An
526
+ unknown environment key, malformed field, unsafe argument, or wrong scope stops before
527
+ the journal is created. Begin holds the
528
+ runtime-plus-instance lock and refuses another unfinished operation. Any corrupt or
529
+ blocked journal fences new mutations and resume until an operator resolves it. Resume is
530
+ same-host only. Intent is durable before an
531
+ external write; observed-applied is durable only after the after-state is verified.
532
+ On restart, the exact pending step is retryable only at its before-state, advances only
533
+ at its after-state, and otherwise blocks as ambiguous. Sensitive file access checks and
534
+ pins its immediate directory. Stale-lock recovery separately pins the operation root
535
+ and locks directory for the full recovery sequence. Creation and destructive cleanup
536
+ also keep the operation root and target directories pinned through their writes. The
537
+ full metadata record is rechecked after the lock and before every non-metadata step.
538
+
539
+ On Windows, a held mutation lock can reuse a native ACL result only for the same
540
+ directory path identity. File checks, every new or resumed lock, and each passive
541
+ inspection check the ACL again. POSIX mode checks remain per-access. This cache does
542
+ not change local mode's trust in the current OS user.
543
+
544
+ The journal states are `prepared`, `snapshotted`, `in-progress`, `applied`, `cleaning`,
545
+ and `committed`; inspection separately reports `resumable`,
546
+ `classification-required`, `blocked`, or `complete`. `committed` means every write was
547
+ verified and every artifact was removed. Cleanup records durable intent per artifact,
548
+ pins and verifies it, unlinks it, and syncs the directory on POSIX; Windows explicitly
549
+ records unavailable directory durability. A missing artifact is safe to resume only
550
+ when cleanup intent predated the attempt. Inspection accepts only two exact crash
551
+ residues: that authorized absence, or the verified after artifact for the current
552
+ intent-recorded step. A terminal manifest removes request, step, digest, locator, and
553
+ artifact metadata. A v4 update retains only its explicit credential-free inverse
554
+ contract. A committed v5 stage retains its credential-free stage contract. A committed
555
+ v6 phase retains its credential-free cutover contract. Completed records remain
556
+ readable across hosts. Repair, update, rollback, uninstall, and endpoint migration use
557
+ this journal. Agent Bridge cannot promise physical erasure
558
+ on SSDs or journaled filesystems, so future commands must minimize credential-bearing
559
+ snapshots and rotate credentials when retained copies contained them. Inspection
560
+ changes no registration, backend, metadata, or snapshot file.
561
+
562
+ The v1 host-adapter manifests are under [`clients/`](clients/). Their compatibility
563
+ field is named `runtime`, but its value identifies the installation target, not a
564
+ unique process. OpenClaw and generic MCP manifests declare the required environment
565
+ variables and command but leave config mutation to the operator because their host
566
+ config shapes vary.
567
+
568
+ The lifecycle ownership boundary and deferred endpoint-migration constraints are
569
+ recorded in [ADR 0004](docs/decisions/0004-client-lifecycle-and-endpoint-migration.md).
570
+
571
+ `clients migrate stage <runtime> --identity <name> --instance <key>
572
+ --enrollment-file <path> --apply` prepares a private gateway successor from a rotation
573
+ enrollment. It does not change the active registration or backend. Staging records
574
+ endpoint digests, credential IDs, the source edge path and scope key, and the
575
+ predecessor grace cutoff without recording tokens or raw gateway URLs.
576
+
577
+ `clients migrate cutover <stage-operation-uuid> --exclusive-edge --apply` consumes a
578
+ committed v5 stage. Before it creates a journal, it verifies both live gateways under
579
+ HTTP 2.1, including the recorded workspace, principal, credential ID, immutable gateway
580
+ authority ID, and the successor credential's `status:read` and `messages:write` grants.
581
+ The endpoints then exchange a direct predecessor-to-successor route challenge. The
582
+ durable journal retains the normalized source gateway URL without a token. Every later
583
+ route challenge uses the successor credential at both URLs, and it drains the source
584
+ edge through the target gateway. The source edge changes to `draining`, receives an
585
+ exclusive lease, and must reach an exact zero-work outbox before any host registration
586
+ changes. The command removes and adds native registrations, or replaces the Claude
587
+ Desktop entry, then changes managed metadata last. It rechecks the authority and lease
588
+ before every host write.
589
+
590
+ Every cutover phase requires `--exclusive-edge`. Agent Bridge can enumerate managed
591
+ registrations that share an edge file, including hardlink aliases, but it cannot see
592
+ unmanaged publishers. The flag records the operator's assertion for that remaining
593
+ cohort. The forward phase also requires an active source edge and an active, empty
594
+ target edge.
595
+
596
+ `clients migrate finalize <cutover-operation-uuid> --exclusive-edge --apply` works
597
+ only after the predecessor grace cutoff and retires the retained source edge. To return
598
+ to an earlier endpoint, first rotate a new owner credential for that endpoint, then run
599
+ an ordinary forward cutover with it as the successor. Use `clients resume
600
+ <operation-uuid>` after a crash. Resume waits for a live drain lease to expire before
601
+ another worker can take it. Dry inspection refuses an edge with live WAL sidecars rather
602
+ than opening it in a mode that could miss uncheckpointed outbox state.
603
+ Moving to an independent database needs a separate owner-mediated process.
604
+ The source backend must name an absolute, normalized edge database file. Relative and
605
+ in-memory edge paths cannot identify one durable outbox and are rejected.
338
606
 
339
607
  [`SKILL.md`](SKILL.md) provides concise runtime-neutral operating instructions for agents. [`llms.txt`](llms.txt) gives tools and model crawlers a compact map of the package, modes, commands, and identity rules.
340
608
 
@@ -575,6 +843,8 @@ Normal inbox and pending reads fall back to the local cache when the gateway is
575
843
  ## CLI
576
844
 
577
845
  ```bash
846
+ agent-bridge --version
847
+ agent-bridge --help
578
848
  agent-bridge init --provider local
579
849
  agent-bridge doctor
580
850
  agent-bridge status
@@ -602,6 +872,10 @@ agent-bridge sync
602
872
  agent-bridge watch
603
873
  ```
604
874
 
875
+ `-h` and `--help` print help before Agent Bridge loads backend configuration or
876
+ dispatches a command. They are safe to use after a command name, including `archive`
877
+ and `dr` commands.
878
+
605
879
  `--project` adds an optional immutable label to a message. It never selects a workspace or changes the active identity. Omit it on reads to include every project and unlabeled messages in the credential-bound workspace. Pass it to `get`, `inbox`, `history`, `pending`, or `watch` for an exact label match. Gateway callers may use `--workspace` only as an assertion. The CLI rejects a mismatch before sending a request. Local mode permits a per-command workspace override. The global legacy Supabase schema has no tenant workspace, so legacy mode fixes workspace to `*` and rejects other `--workspace` values.
606
880
 
607
881
  History defaults to mailbox `inbox`: broadcasts plus messages targeted to the configured principal, exactly as prior releases did. `sent` selects messages whose source is that principal, and `all` is the union. `--receipt-state any|unread|read` is caller-relative and valid only with `inbox`. The deprecated `--unacked-by` option remains an identity assertion. The CLI rejects a mismatch before opening storage or contacting a gateway. Server surfaces reject it before querying message storage. Cursors bind workspace, principal, mailbox, and normalized filters. Version 1 cursors are temporarily accepted, while all new cursors are version 2.
@@ -647,6 +921,22 @@ The acknowledgment names depend on the interface. MCP `ack_context` and CLI `ack
647
921
  ## Identity and security
648
922
 
649
923
  - `~/.agent-bridge/config` contains backend settings only. A stored `AGENT_BRIDGE_AGENT` value is ignored.
924
+ - Workspace is the tenant boundary. Principal is the durable agent identity and message source.
925
+ - `AGENT_BRIDGE_INSTANCE` is an optional caller-supplied stable consumer key. Supported
926
+ installers generate and persist one for each installed client. Direct clients should
927
+ do the same when they need separate consumer state or presence.
928
+ - Unless `AGENT_BRIDGE_CURSOR` sets an explicit path, a present instance key selects
929
+ the cursor path. The key also selects the delivery lease owner and presence row.
930
+ Processes that share a key also share those resources. The gateway does not bind the
931
+ key to an installer registration. It is not a PID, unique live process, or
932
+ conversation ID.
933
+ - When the key and explicit cursor path are both omitted, cursor storage uses
934
+ `default`. Delivery leases fall back to the principal, and presence operations reject
935
+ the request because presence requires an instance key.
936
+ - Presence is instance-keyed in the released protocol. Per-process presence requires
937
+ an additive identity instead of a silent change to lease ownership or cursor paths.
938
+ - Session and thread identifiers are message and application context. They do not
939
+ select credentials, workspace, principal, or delivery ownership.
650
940
  - Local clients bind identity through their process environment or an explicit CLI send argument.
651
941
  - Gateway tokens bind workspace and principal. The API ignores caller-supplied source and workspace fields.
652
942
  - Gateway clients use separate owner-only backend files and principal-bound tokens.
@@ -654,7 +944,8 @@ The acknowledgment names depend on the interface. MCP `ack_context` and CLI `ack
654
944
  - Remote HTTP must use TLS. Plain HTTP is accepted only on loopback.
655
945
  - Local config, database, WAL, and shared-memory files use owner-only permissions where the platform supports POSIX modes.
656
946
  - The private `agent_bridge` schema is denied to Supabase `anon` and `authenticated` Data API roles.
657
- - Expired presence rows are pruned during heartbeat and listing. Each agent is capped at 128 active instances, and each workspace is capped at 4,096.
947
+ - Expired instance-presence rows are pruned during heartbeat and listing. Each agent
948
+ is capped at 128 active instance keys, and each workspace is capped at 4,096.
658
949
  - Errors expose stable codes without database URLs, tokens, or provider response bodies.
659
950
  - Delivery work is at least once, not exactly once. Consumers must make external side effects idempotent.
660
951
 
@@ -681,7 +972,7 @@ The original v1 schema remains in [`sql/setup.sql`](sql/setup.sql). Ordered gate
681
972
  `status` is a passive snapshot. It does not synchronize or probe a remote provider. An unprobed remote reports `status: "unknown"`, `connected: false`, and `remoteReachable: null`. Passive status still exits 0. `doctor` evaluates named checks and exits 0 for `ok`, 2 for `degraded`, and 1 for `failed`. Both return JSON with:
682
973
 
683
974
  - Provider and actual schema version.
684
- - Bound workspace, agent, and instance.
975
+ - Bound workspace, agent, and consumer instance key.
685
976
  - Endpoint or database path.
686
977
  - Cursor and queue state.
687
978
  - Pending, claimed, retrying, and dead delivery counts, plus due versus scheduled work, expired leases, oldest-due time, and bounded queue lag.
@@ -700,6 +991,8 @@ Each gateway operation checks the scopes in the canonical registry. `capabilitie
700
991
 
701
992
  Migration 012 makes PostgreSQL the authority for each production gateway request that passes credential preflight. Node hashes the bearer credential before PostgreSQL receives it. The gateway checks out one connection, opens one explicit transaction, matches the credential ID and hash inside a narrow security-definer function, and derives the workspace, principal, and scopes from current database state. Security accounting and domain work share that transaction and backend. Delivery claim, cancel, and requeue reuse it without nested `BEGIN`. Runtime logins cannot read credential hashes, agent records, workspace records, or request-authority records.
702
993
 
994
+ Migration 017 adds one immutable PostgreSQL authority UUID. The released request-authority opener keeps its return shape. Production gateway requests use a bound opener that returns the authority UUID with the database-derived credential. Authenticated gateway `/v2/status` replies include `gatewayAuthorityId` and `credentialId` when transaction-bound request authority is active. Authenticated HTTP 2.1 capabilities return `grantedScopes` for that credential. Migration 018 uses the same bound authority to issue and consume an expiring challenge for a direct credential successor. Migration 019 also permits the same active successor credential at both endpoints after a cutover journal begins. Neither challenge proves a database migration or authorizes endpoint cutover.
995
+
703
996
  Migration 013 enables and forces row-level security on messages, receipts, deliveries, delivery events, and presence. Policies read workspace and principal from the transaction-bound request authority. The runtime role cannot set that authority through session variables, inherit a table-owner role, or bypass RLS. Separate no-login roles own domain tables, read request context, and write delivery audit events. Delivery identity and publisher bindings are immutable. A trigger lets recipients perform recipient lifecycle actions and reserves cancel and requeue for publishers.
704
997
 
705
998
  The migration records a catalog attestation after it creates the policies, constraints, triggers, and security functions. `/readyz` fails if the current catalog no longer matches that owner-created baseline. Gateway capabilities report `rowIsolation: true` only when request authority is enabled and the migration, catalog attestation, ownership, policy, privilege, and function checks all pass. An owner-approved schema change must update the attestation in its migration.
@@ -740,14 +1033,27 @@ The runtime role owns no schema objects. PostgreSQL keeps roles after a database
740
1033
  ```bash
741
1034
  npm run typecheck
742
1035
  npm test
1036
+ npm run test:postgres:preflight
743
1037
  npm run build
744
1038
  npm pack
745
1039
  ```
746
1040
 
747
- Set `AGENT_BRIDGE_TEST_DATABASE_URL` to run the live PostgreSQL contract and migration
748
- tests. CI runs Node 22 and 24 on Linux, macOS, and Windows. PostgreSQL 15 through 18 each
749
- pack and install the npm tarball, register a least-privilege operator, and exercise
750
- owner provision, inventory, rotation, and revocation. Before applying a Windows DACL,
1041
+ The PostgreSQL preflight starts a fresh Docker container for each supported major,
1042
+ assigns a free loopback port, and runs the live contract. Normal completion removes
1043
+ each container. A later run removes labeled preflight containers older than two hours,
1044
+ which bounds residue after a process or machine stops before cleanup can run. Use
1045
+ `npm run test:postgres:preflight -- --major 16` for one major, or
1046
+ `npm run test:postgres:preflight:full` for the full suite on every major. The command
1047
+ requires a running Docker engine and never reuses a database from an earlier run.
1048
+
1049
+ Set `AGENT_BRIDGE_TEST_DATABASE_URL` when an existing disposable PostgreSQL database is
1050
+ more convenient. CI runs one PostgreSQL 16 contract before starting the 15 through 18
1051
+ jobs. Each version then runs the live contract and matching native DR proof. The package
1052
+ job builds and installs the npm tarball separately.
1053
+
1054
+ CI runs Node 22 and 24 on Linux, macOS, and Windows. One native Windows contract checks
1055
+ private paths, managed uninstall path identity, and recovery before the two Windows jobs
1056
+ start. Before applying a Windows DACL,
751
1057
  private paths must be owned by the current account SID or the active token's default
752
1058
  owner SID. The final owner and sole protected FullControl rule must use the account SID.
753
1059
  Verification-only paths must already satisfy that final policy. Node file identity
@@ -759,11 +1065,13 @@ durability behavior has not yet been proved on a dedicated Windows host.
759
1065
  ## Documentation
760
1066
 
761
1067
  - [ROADMAP.md](ROADMAP.md): released work, unreleased implementation, and the remaining program.
762
- - [SECURITY.md](SECURITY.md): supported versions, private vulnerability reporting, and security boundaries.
1068
+ - [SECURITY.md](SECURITY.md): supported versions, release integrity, private vulnerability reporting, and security boundaries.
763
1069
  - [docs/ecosystem.md](docs/ecosystem.md): product boundary, adjacent systems, and interoperability direction.
764
1070
  - [docs/troubleshooting.md](docs/troubleshooting.md): MCP startup, identity, backend, and client recovery.
1071
+ - [docs/deployment.md](docs/deployment.md): Compose development setup, production constraints, upgrades, backup, and rollback.
765
1072
  - [ADR-0001](docs/decisions/0001-protocol-layers-and-acknowledgment-semantics.md): protocol layers and acknowledgment semantics.
766
1073
  - [ADR-0002](docs/decisions/0002-canonical-operation-contract-registry.md): canonical contracts, generated artifacts, discovery, and version negotiation.
1074
+ - [ADR-0003](docs/decisions/0003-host-adapters-and-consumer-instance-keys.md): host layers and consumer instance-key semantics.
767
1075
  - [docs/architecture-v2.md](docs/architecture-v2.md): protocol and storage decisions.
768
1076
  - [SKILL.md](SKILL.md): runtime-neutral agent operating instructions.
769
1077
  - [llms.txt](llms.txt): compact machine-readable project map.
package/ROADMAP.md CHANGED
@@ -9,17 +9,18 @@ published and the supported clients pass a fresh end-to-end check.
9
9
 
10
10
  ## Status
11
11
 
12
- ### Released in 0.2.0
12
+ ### Released by 0.3.1
13
13
 
14
14
  - Local SQLite and shared PostgreSQL storage behind provider-neutral interfaces.
15
15
  - An authenticated HTTPS gateway and a named legacy Supabase adapter.
16
16
  - Immutable messages, caller receipts, delivery leases, retries, dead letters, and
17
17
  presence.
18
18
  - Durable SQLite edge outbox and inbox cache for gateway clients.
19
- - CLI, MCP, Codex, Claude Code, and Claude Desktop integration paths.
20
-
21
- ### Implemented for the next release
22
-
19
+ - CLI, MCP, HTTPS, and Node library access surfaces.
20
+ - Installed-package version reporting through `agent-bridge --version` and `-V`.
21
+ - Automated host adapters for Codex, Claude Code, and Claude Desktop. The Codex
22
+ adapter configures the profile shared by the Codex CLI and the Codex surface in the
23
+ ChatGPT desktop app.
23
24
  - Caller-bound inbox, sent, and combined history with scope-bound cursors.
24
25
  - Publisher-owned delivery policy, priority claims, cancel, requeue, and delivery event
25
26
  inspection.
@@ -34,13 +35,68 @@ published and the supported clients pass a fresh end-to-end check.
34
35
  - Portable workspace archives across canonical SQLite and PostgreSQL stores.
35
36
  - Native SQLite and PostgreSQL backup, verification, and restore.
36
37
 
37
- ### Required before the next release is complete
38
-
39
- - Merge the development branch through the protected-main checks.
40
- - Publish the package through the configured npm OIDC workflow.
41
- - Prove Codex, Claude Code, and Claude Desktop startup, send, receive, receipt, claim,
42
- settlement, offline replay, and restart behavior against the released package.
43
- - Move the project's own normal traffic to v2 while retaining a tested v1 rollback path.
38
+ ### 0.4.0 package contents
39
+
40
+ The published npm version is the authority for whether this package line has shipped.
41
+
42
+ - Read-only lifecycle inspection and explicit, plan-first adoption for the Codex,
43
+ Claude Code, and Claude Desktop adapters, backed by owner-only credential-free
44
+ managed metadata, private backend-path verification, health-neutral exact
45
+ registration comparison, immutable nonsecret host locators, and a re-inspected
46
+ adoption postcondition.
47
+
48
+ - Plan-first managed-client repair, update, and forward-only uninstall for Codex, Claude Code, and Claude
49
+ Desktop. Mutation authority comes only from strict private metadata selected by
50
+ runtime and instance, then bound to the exact managed identity. Applied work uses
51
+ the crash-safe journal, fixed-key credential-free update requests, full metadata and
52
+ bounded registration proofs, exact restart classification, monotonic POSIX backend
53
+ privacy repair, and metadata-last launch updates. Windows accepts only an already
54
+ private backend path. Uninstall removes the registration, backend, and metadata in
55
+ that order without rollback. It refuses a backend that still needs privacy repair.
56
+ Desktop publication and deletion have a documented same-user advisory race.
57
+ New updates use v4 journals and retain a bounded credential-free inverse contract.
58
+ `clients rollback <update-operation-id> --identity <name>` is plan-first and, with
59
+ `--apply`, creates a separate reverse journal after it proves the recorded forward
60
+ state. Generic `clients resume` derives authority from recorded v3, supported v4,
61
+ v5 migration-stage, and v6 endpoint-migration requests. Repair remains monotonic
62
+ and uninstall recovery is re-enrollment.
63
+
64
+ - Gateway-client migration staging, cutover, and finalization for managed
65
+ clients. A v5 stage creates a private successor backend without changing the active
66
+ host registration. A v6 cutover verifies one live gateway authority and a route
67
+ challenge, drains the source SQLite edge under a lease, changes the host registration
68
+ and metadata, and preserves credential-free contracts for restart classification.
69
+ After journal creation, cutover proves both routes with the successor credential and
70
+ drains the source edge through the target gateway. Finalize retires the retained
71
+ source after the predecessor grace cutoff. Return to an earlier endpoint requires a
72
+ new owner rotation and a new forward cutover. Each phase requires a fresh
73
+ `--exclusive-edge` assertion because unmanaged publishers cannot be enumerated.
74
+
75
+ - Gateway-only HTTP 2.1 endpoint-migration challenge operations. An active issuer and
76
+ direct active successor use a 64-character challenge bound to the immutable gateway
77
+ authority UUID. PostgreSQL stores only a domain-separated commitment for at most 60
78
+ seconds. A consumed cross-route challenge proves that both live routes share its
79
+ short-lived database state. It does not authorize endpoint cutover or prove a
80
+ historical database move.
81
+
82
+ - A pinned, non-root gateway image and a Compose development stack with ordered
83
+ migration, restricted runtime-role bootstrap, health checks, private secret files,
84
+ and a persistent PostgreSQL volume.
85
+ - A Linux Compose acceptance test that provisions two temporary principals and proves
86
+ authority binding, delivery settlement, denied runtime access to credential hashes,
87
+ idempotent restart, and PostgreSQL volume persistence.
88
+ - A production deployment guide covering TLS, network exposure, secret separation,
89
+ backups, upgrade order, and schema rollback limits.
90
+
91
+ ### Post-release validation and adoption
92
+
93
+ - Move the project's own normal traffic to the authenticated gateway while retaining a
94
+ tested legacy rollback path.
95
+ - Prove cross-machine claim, settlement, offline replay, and restart behavior against
96
+ the published package and a deployed v2 gateway. The historical 0.3.0 live release
97
+ check covered startup, private mailbox sends, caller-scoped history, receipts, and
98
+ client restart through the legacy compatibility backend. It did not prove
99
+ gateway-only behavior.
44
100
  - Replace remaining direct legacy table pollers with the v2 cursor protocol.
45
101
  - Confirm the README, npm metadata, GitHub metadata, release notes, and package contents
46
102
  match the released artifact.
@@ -49,9 +105,6 @@ published and the supported clients pass a fresh end-to-end check.
49
105
 
50
106
  ### Installation and operations
51
107
 
52
- - Add client repair, update, uninstall, and registration diagnostics.
53
- - Provide a Compose-based development deployment and a production deployment guide.
54
- - Add endpoint migration tooling that does not strand an existing SQLite outbox.
55
108
  - Publish a maintained client compatibility matrix.
56
109
 
57
110
  ### Storage lifecycle and observability
@@ -64,6 +117,11 @@ published and the supported clients pass a fresh end-to-end check.
64
117
 
65
118
  ### Presence and wakeups
66
119
 
120
+ - Separate the stable consumer instance key from a live process identity. Supported
121
+ installers generate one key per installed client, while direct clients may supply
122
+ their own. Processes that share a key also share presence in 0.3.
123
+ - Add per-process presence and session correlation only through an additive protocol
124
+ change with migration and conformance coverage.
67
125
  - Maintain heartbeat and expiry automatically for supported long-lived clients.
68
126
  - Add wake adapters only where they reduce latency. Lost wakeups must never lose data.
69
127
  - Keep cursored pull as the authoritative recovery path.
@@ -83,7 +141,11 @@ published and the supported clients pass a fresh end-to-end check.
83
141
  - Carry A2A envelopes without implementing a competing task state machine.
84
142
  - Publish conformance fixtures and an adapter template.
85
143
  - Add client libraries where real integrations need them.
86
- - Expand runtime installers after each host has a stable configuration contract.
144
+ - Rename the compatibility `runtime` manifest key to an explicit host-adapter key in a
145
+ versioned manifest contract.
146
+ - Expand host installers after each product has a stable configuration contract.
147
+ Hermes, Pi, and similar harnesses can use a generic access surface when their host
148
+ supports one, but they do not have a dedicated adapter or conformance claim.
87
149
 
88
150
  See [docs/ecosystem.md](docs/ecosystem.md) for the product boundary.
89
151