@uchibeke/gallivant 0.0.0-stage → 0.2.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 (168) hide show
  1. package/CONTRIBUTING.md +26 -0
  2. package/LICENSE +204 -0
  3. package/README.md +201 -2
  4. package/SECURITY.md +19 -0
  5. package/bin/gallivant.mjs +257 -0
  6. package/bin/package-plugin.mjs +16 -0
  7. package/bin/release-live.mjs +29 -0
  8. package/bin/release-package.mjs +23 -0
  9. package/bin/session-runtime.mjs +13 -0
  10. package/bin/task-delivery-state.mjs +12 -0
  11. package/docs/README.md +70 -0
  12. package/docs/agent-setup.md +214 -0
  13. package/docs/app.md +111 -0
  14. package/docs/architecture.md +265 -0
  15. package/docs/chains.md +102 -0
  16. package/docs/codex-cloud.md +284 -0
  17. package/docs/commands.md +620 -0
  18. package/docs/config.md +430 -0
  19. package/docs/execution.md +796 -0
  20. package/docs/guardrails.md +311 -0
  21. package/docs/install.md +338 -0
  22. package/docs/launch.md +42 -0
  23. package/docs/learning.md +369 -0
  24. package/docs/network-recovery.md +101 -0
  25. package/docs/openai-agents.md +457 -0
  26. package/docs/prd.md +246 -0
  27. package/docs/preparation.md +110 -0
  28. package/docs/release-qualification.md +196 -0
  29. package/docs/releasing.md +140 -0
  30. package/docs/runtime-environment.md +113 -0
  31. package/docs/task-delivery.md +476 -0
  32. package/docs/tasks.md +739 -0
  33. package/lib/aport.mjs +95 -0
  34. package/lib/attribution.mjs +95 -0
  35. package/lib/block.mjs +89 -0
  36. package/lib/capabilities.mjs +3 -0
  37. package/lib/chains.mjs +222 -0
  38. package/lib/codex_cloud.mjs +160 -0
  39. package/lib/codex_cloud_config.mjs +20 -0
  40. package/lib/codex_cloud_input.mjs +49 -0
  41. package/lib/codex_cloud_result.mjs +74 -0
  42. package/lib/commands/doctor.mjs +457 -0
  43. package/lib/commands/init.mjs +34 -0
  44. package/lib/commands/learn.mjs +54 -0
  45. package/lib/commands/new.mjs +47 -0
  46. package/lib/commands/ready.mjs +45 -0
  47. package/lib/commands/register.mjs +195 -0
  48. package/lib/commands/resume.mjs +224 -0
  49. package/lib/commands/serve.mjs +349 -0
  50. package/lib/commands/start.mjs +247 -0
  51. package/lib/commands/start_services.mjs +22 -0
  52. package/lib/commands/status.mjs +150 -0
  53. package/lib/commands/task.mjs +73 -0
  54. package/lib/commands/up.mjs +228 -0
  55. package/lib/commands/why.mjs +143 -0
  56. package/lib/config.mjs +461 -0
  57. package/lib/context.mjs +100 -0
  58. package/lib/control.mjs +202 -0
  59. package/lib/control_contract.mjs +16 -0
  60. package/lib/coordinator.mjs +19 -0
  61. package/lib/credential.mjs +161 -0
  62. package/lib/daemon.mjs +156 -0
  63. package/lib/deliverable.mjs +357 -0
  64. package/lib/events.mjs +261 -0
  65. package/lib/executable.mjs +31 -0
  66. package/lib/execution.mjs +631 -0
  67. package/lib/execution_contract.mjs +15 -0
  68. package/lib/execution_input.mjs +4 -0
  69. package/lib/execution_io.mjs +94 -0
  70. package/lib/execution_journal.mjs +69 -0
  71. package/lib/execution_preparation.mjs +29 -0
  72. package/lib/execution_result.mjs +266 -0
  73. package/lib/fs.mjs +133 -0
  74. package/lib/gh.mjs +289 -0
  75. package/lib/git.mjs +434 -0
  76. package/lib/harness.mjs +521 -0
  77. package/lib/harness_log.mjs +432 -0
  78. package/lib/hash.mjs +16 -0
  79. package/lib/identity.mjs +98 -0
  80. package/lib/learning.mjs +654 -0
  81. package/lib/learning_contract.mjs +2 -0
  82. package/lib/learning_data.mjs +135 -0
  83. package/lib/learning_input.mjs +111 -0
  84. package/lib/learning_qualification.mjs +67 -0
  85. package/lib/learning_signer.mjs +151 -0
  86. package/lib/learning_store.mjs +88 -0
  87. package/lib/log.mjs +53 -0
  88. package/lib/network_diagnostics.mjs +64 -0
  89. package/lib/network_recovery.mjs +42 -0
  90. package/lib/notify.mjs +58 -0
  91. package/lib/openai_agents.mjs +373 -0
  92. package/lib/openai_agents_config.mjs +14 -0
  93. package/lib/openai_agents_http.mjs +87 -0
  94. package/lib/openai_agents_input.mjs +15 -0
  95. package/lib/openai_agents_sources.mjs +112 -0
  96. package/lib/owner_delivery.mjs +443 -0
  97. package/lib/plugin_package.mjs +340 -0
  98. package/lib/prd.mjs +635 -0
  99. package/lib/preparation_agents.mjs +33 -0
  100. package/lib/preparation_codex.mjs +212 -0
  101. package/lib/probe.mjs +126 -0
  102. package/lib/prompt.mjs +238 -0
  103. package/lib/provider_health.mjs +55 -0
  104. package/lib/public-format.mjs +31 -0
  105. package/lib/public_output.mjs +49 -0
  106. package/lib/release_package.mjs +154 -0
  107. package/lib/repository_files.mjs +86 -0
  108. package/lib/run.mjs +385 -0
  109. package/lib/run_log.mjs +94 -0
  110. package/lib/runtime-environment.mjs +87 -0
  111. package/lib/runtime_dependencies.mjs +15 -0
  112. package/lib/runtime_node.mjs +107 -0
  113. package/lib/runtime_state.mjs +174 -0
  114. package/lib/sources/index.mjs +27 -0
  115. package/lib/sources/prd.mjs +50 -0
  116. package/lib/start_contract.mjs +37 -0
  117. package/lib/state.mjs +246 -0
  118. package/lib/task_allowance.mjs +31 -0
  119. package/lib/task_completion.mjs +61 -0
  120. package/lib/task_contract.mjs +450 -0
  121. package/lib/task_delivery.mjs +219 -0
  122. package/lib/task_delivery_cancel.mjs +34 -0
  123. package/lib/task_delivery_contract.mjs +61 -0
  124. package/lib/task_delivery_mcp.mjs +40 -0
  125. package/lib/task_delivery_store.mjs +43 -0
  126. package/lib/task_delivery_view.mjs +88 -0
  127. package/lib/task_environment.mjs +281 -0
  128. package/lib/task_prepare.mjs +224 -0
  129. package/lib/task_store.mjs +38 -0
  130. package/lib/tasks.mjs +513 -0
  131. package/lib/tick.mjs +1635 -0
  132. package/lib/time.mjs +36 -0
  133. package/lib/tracker/assets.mjs +43 -0
  134. package/lib/tracker/pages.mjs +320 -0
  135. package/lib/tracker/runs.mjs +102 -0
  136. package/lib/tracker/stream.mjs +74 -0
  137. package/lib/tracker_process.mjs +107 -0
  138. package/lib/verification_sandbox.mjs +181 -0
  139. package/node_modules/smol-toml/LICENSE +24 -0
  140. package/node_modules/smol-toml/README.md +605 -0
  141. package/node_modules/smol-toml/dist/date.d.ts +41 -0
  142. package/node_modules/smol-toml/dist/date.js +156 -0
  143. package/node_modules/smol-toml/dist/error.d.ts +37 -0
  144. package/node_modules/smol-toml/dist/error.js +67 -0
  145. package/node_modules/smol-toml/dist/extract.js +289 -0
  146. package/node_modules/smol-toml/dist/index.cjs +770 -0
  147. package/node_modules/smol-toml/dist/index.d.ts +44 -0
  148. package/node_modules/smol-toml/dist/index.js +34 -0
  149. package/node_modules/smol-toml/dist/parse.d.ts +73 -0
  150. package/node_modules/smol-toml/dist/parse.js +164 -0
  151. package/node_modules/smol-toml/dist/primitive.js +151 -0
  152. package/node_modules/smol-toml/dist/stringify.d.ts +32 -0
  153. package/node_modules/smol-toml/dist/stringify.js +219 -0
  154. package/node_modules/smol-toml/dist/struct.js +156 -0
  155. package/node_modules/smol-toml/dist/util.d.ts +43 -0
  156. package/node_modules/smol-toml/dist/util.js +57 -0
  157. package/node_modules/smol-toml/package.json +68 -0
  158. package/npm-shrinkwrap.json +1823 -0
  159. package/package.json +105 -4
  160. package/templates/claude-settings.json +18 -0
  161. package/templates/passport.gallivant.json +83 -0
  162. package/templates/plugin/bundled-runtime.json +26 -0
  163. package/templates/plugin/schemas/mcp.schema.json +120 -0
  164. package/templates/plugin/schemas/plugin.schema.json +65 -0
  165. package/templates/plugin/task-delivery.SKILL.md +60 -0
  166. package/templates/prd.md +32 -0
  167. package/templates/tracker/tracker.css +301 -0
  168. package/templates/tracker/tracker.js +721 -0
@@ -0,0 +1,476 @@
1
+ # Embed task delivery in another application
2
+
3
+ The package exposes Gallivant's task/readiness/review decisions and provider
4
+ transports to a trusted host through a scoped operation API or MCP. The host
5
+ supplies authentication and authorization, tenant/region routing, repository
6
+ authority, HTTP transport, durable storage, scheduling and any web/plugin UI.
7
+ Installing the package does not deploy a service or configure those boundaries.
8
+
9
+ **APort is the reference integration**, not a required host for these exports.
10
+ The examples below use its injected adapters and deployment names; another host
11
+ must enforce the same authorization, ownership, persistence and recovery
12
+ contracts. In the APort integration, APort owns publication and the host
13
+ responsibilities above. Its existing
14
+ `aporthq/agent-passport/aport-task-delivery-mcp` job produced merged
15
+ [PR #414](https://github.com/aporthq/agent-passport/pull/414); reuse that integration.
16
+ The M5/M6 notes below preserve that integration's milestone evidence and gates;
17
+ they do not certify another host or supply a public UI, database or competing
18
+ runner.
19
+
20
+ ## Installed exports
21
+
22
+ Core `0.2.0`, task schema `1`, execution schema `1`, operation schema `1`.
23
+ The candidate digest comes from the emitted `runtime.json`/`manifest.json`;
24
+ pin the artifact produced from the eventual human-merged commit, not this branch.
25
+
26
+ | Import | Public API |
27
+ | --- | --- |
28
+ | `@uchibeke/gallivant/tasks` | `createTaskService`, `TASK_VERSION`; same service used by CLI task commands |
29
+ | `@uchibeke/gallivant/capabilities` | `executionCapabilities`, `capabilitiesFor`, setup/runtime requirements |
30
+ | `@uchibeke/gallivant/task-delivery` | `createTaskDelivery` scoped operation dispatcher |
31
+ | `@uchibeke/gallivant/task-delivery/contracts` | `TASK_OPERATIONS`, versions, compatibility handshake, UI resource configuration |
32
+ | `@uchibeke/gallivant/task-delivery/views` | `taskView`, `modelSummary`; saved observations only |
33
+ | `@uchibeke/gallivant/task-delivery/store` | `createDeliveryStore`, `scopeKey`; single-host durable receipt adapter |
34
+ | `@uchibeke/gallivant/task-delivery/mcp` | `registerTaskDelivery`; lazy optional MCP SDK peer `1.32.1` |
35
+ | `@uchibeke/gallivant/execution` | Existing `makeExecution`, cached inspect and coordinator reconciliation |
36
+ | `@uchibeke/gallivant/providers/openai-agents` | Existing managed session transport and setup checks |
37
+ | `@uchibeke/gallivant/providers/codex-cloud` | Existing native CLI transport and setup checks |
38
+ | `@uchibeke/gallivant/runtime/coordinator` | `createCoordinator` fenced bounded wake envelope |
39
+ | `@uchibeke/gallivant/runtime/node` | `createNodeOwnerStore`, `createNodeCoordinator`, requirements |
40
+ | `@uchibeke/gallivant/runtime/state` | Check, migrate, private backup and fresh-namespace rollback |
41
+ | `@uchibeke/gallivant/runtime/node/dependencies` | State/config/log/identity constructors, canonical tick/readiness/controls, bounded log reader and atomic storage helpers for injected Node adapters |
42
+ | `@uchibeke/gallivant/plugin-package` | Single reproducible package builder and public metadata validator |
43
+
44
+ Imports read no operator configuration, invoke no provider and start no daemon.
45
+ Existing `./lib/*` compatibility imports remain; consumers use the named exports.
46
+ No new CLI daemon is required. Existing registry/run/source files, tracker routes,
47
+ Command Center SSE/history, statuses and controls retain their version-1 shapes.
48
+
49
+ ## Scoped operation adapter
50
+
51
+ ```js
52
+ import { createTaskDelivery } from '@uchibeke/gallivant/task-delivery';
53
+ import { createDeliveryStore } from '@uchibeke/gallivant/task-delivery/store';
54
+ const delivery = createTaskDelivery({
55
+ manifest: emittedRuntimeManifest, // load this installed artifact's runtime.json
56
+ authorize: aportAuthorize, // validate OAuth/audience/region/repository on EVERY call
57
+ contextFor: aportScopedNodeContext,
58
+ store: createDeliveryStore('/durable/preview/delivery'),
59
+ schedule: aportEnqueueWake,
60
+ secretsFor: aportPrivateRedactionValues,
61
+ });
62
+ const task = await delivery.dispatch('prepare', {
63
+ repositoryId: 'widget', harness: 'openai-agents',
64
+ text: 'Describe the requested implementation and its constraints.',
65
+ completion: { target: 'delivery_ready' }, // optional; default shown
66
+ allowance: { budgetUsd: 1, runtimeMs: 60000 },
67
+ operationId: 'request-1', expectedRevision: 0,
68
+ }, authenticatedIdentity);
69
+ ```
70
+
71
+ `authorize` must return validated `tenant`, `account`, `environment`, `region`,
72
+ `scopes` (`task-delivery:read` or `task-delivery:write`) and authorized repository
73
+ IDs. Identity comes from APort's authenticated request context, never tool input.
74
+ `contextFor(scope, repositoryId)` supplies `{ctx, repository:{dir,repo,context}}`.
75
+ Each context and durable home must be isolated by all four scope dimensions;
76
+ credential/GitHub/provider resolution must enforce the same scope. Selected
77
+ context IDs map to trusted repository paths. No paths, endpoints or credentials
78
+ are accepted by the public schemas. Do not supply `taskOptions` in production;
79
+ that dependency injection seam is used by deterministic consumer fixtures.
80
+
81
+ The durable receipt store interface is `read(scope)` and
82
+ `transaction(scope, async (data, save) => result)`; `save` must commit before it
83
+ resolves. It serializes the scope for the entire mutation and retains task
84
+ ownership, exact request fingerprints, intent, acknowledgement and pending wake.
85
+ This release's filesystem adapter supports one host on a durable volume. APort
86
+ can supply another adapter only with equivalent tested transaction/ownership
87
+ semantics. Shared physical storage alone grants no authority.
88
+ Delivery mutations also claim the scoped home's daemon ownership lock before
89
+ saving intent and hold it through task effects, receipt acknowledgement and wake
90
+ scheduling. Backup, migration and coordinator wakes therefore refuse concurrent
91
+ ownership; retry the same operation ID after the owner releases. The scheduler
92
+ must enqueue a future wake, never execute a coordinator inline. Read operations
93
+ do not acquire this owner or create provider pollers.
94
+ The dispatcher requires its own emitted `runtime.json` as `manifest`; it captures
95
+ that identity at construction and checks the exact installed version/digest under
96
+ ownership on every mutation, including receipt replays. Migrate each scoped home
97
+ before enabling requests. After migration to another artifact, retire old request
98
+ handlers; never substitute the namespace's new pin as an old handler's manifest.
99
+ Consumers upgrading from the earlier dispatcher signature must add this manifest
100
+ and initialize the scoped pin. Reads do not validate or replace that pin.
101
+
102
+ Capability responses expose `repositories[].completion` with `defaultTarget` and
103
+ supported `targets`. The shared prepare schema accepts only
104
+ `completion: { target: 'delivery_ready' | 'integrated' }`; the selected policy is
105
+ persisted through intake and implementation ownership. Task, list, model and
106
+ evidence projections expose `completion` from saved coordinator observations.
107
+ For `delivery_ready`, a qualified saved handoff stops automatic observation and
108
+ fixes. Explicit queued controls reopen the normal workflow. `integrated` and
109
+ legacy runs retain monitoring. Host schedulers use the exported
110
+ `coordinatorEntryActive` predicate instead of treating every `ready-for-human`
111
+ entry as active; the predicate requires matching repository, PR, base, head and
112
+ gate proof. Read `completion.monitoring` for the saved view's monitoring status.
113
+ Use `completion.status`, not a provider success or a terminal PR state, to report
114
+ fulfillment. `awaiting_integration` means the qualified PR is still being watched;
115
+ `blocked` or `unverified` requires attention. Both targets use the GitHub PR
116
+ observation adapter today. The milestone names are portable, but no additional
117
+ artifact, deployment or non-GitHub adapter is advertised. See [task milestones](tasks.md#choose-the-delivery-milestone)
118
+ for evidence, cancellation and legacy behavior. The policy never grants merge
119
+ permission or changes the allowance.
120
+
121
+ New natural-language publication clauses use the core's versioned exact-source
122
+ ownership contract. `completion.obligations` exposes their pending/fulfilled state
123
+ and matching coordinator evidence. `TASK_DELIVERY_SCOPE` is a before-effects
124
+ clarification refusal, durably acknowledged on the exact operation identity; it
125
+ must not be retried with changed text under that same identity. Ask the owner to
126
+ clarify the complete request and then use a new preparation identity. See
127
+ [natural-language ownership](tasks.md) for supported syntax and limitations.
128
+
129
+ Literal examples must have matching quote/backtick delimiters in new requests and
130
+ answers. Saved ownership contracts keep their approved spans and historical
131
+ unclosed-literal handling. Malformed mixed backtick runs that previously exposed a
132
+ publication clause can fail validation under the corrected scanner; their records
133
+ are not rewritten. The owner must clarify a new request rather than automatically
134
+ continuing publication from that malformed contract. PR-modified UI/document objects, database transactions, data
135
+ structure operations and product-user consent are implementation requirements;
136
+ unqualified Git directions, owner approval and publication conditions remain
137
+ workflow controls. Only those concrete technical objects are excluded: unrelated
138
+ or coordinated restrictions remain visible. Statement separators end independent
139
+ constraints, while an unfinished colon prefix keeps its scope across blank lines.
140
+ This is a bounded grammar, not a general natural-language authorization model.
141
+
142
+ All mutations require operationId and expectedRevision; prepare uses revision 0.
143
+ Preparation does not authorize implementation. Start requires `run:true` and the
144
+ current exact readiness decision. Answers bind saved question IDs. Stable keys
145
+ replay saved results; changed payloads conflict. Lost execution acknowledgement
146
+ retains the existing dispatch intent and cannot automatically submit twice.
147
+ Controls call the same queue as CLI/tracker and carry stable request identity.
148
+ The scheduler may retry a pending wake without repeating inference.
149
+ Scoped allowance is pinned into implementation metadata after subtracting
150
+ preparation charges/reservations and elapsed time. Later runs use the saved cap,
151
+ subtract known local charges and completed runtime, and retain the remote
152
+ execution ledger's aggregate reservations. Unknown local cost or duration refuses
153
+ further dispatch. Providers without billing hard caps remain explicitly described
154
+ as such; an authorization limit is not a promise about their billing controls.
155
+
156
+ Tools are generated from `TASK_OPERATIONS`: capabilities, prepare, answer,
157
+ resume, validate, start, list, inspect, evidence, logs and control. MCP SDK
158
+ registration prefixes each name with `task_`; there is one schema/annotation
159
+ mapping. Preparation, readiness, start and controls are writes with external
160
+ effects. Reads inspect saved state and create no provider poller. MCP registration
161
+ expects APort's per-request `identityFor` and authorized built `readResource`.
162
+ Capabilities return at most 100 authorized repositories, sorted by opaque ID,
163
+ with `truncated` and `nextCursor`. Pass `nextCursor` as `cursor` to continue;
164
+ a null cursor ends the traversal. Every page reauthorizes the account. Repository
165
+ IDs and provider availability, preparation, setup, cost and control fields appear in both
166
+ MCP model content and UI metadata, so a client can construct `prepare` directly.
167
+ The optional cursor extends operation schema version 1 without changing existing
168
+ empty-input calls. Restart discovery to include newly granted IDs before a cursor.
169
+
170
+ APort owns transport-level OAuth discovery/challenges, origin/audience validation,
171
+ credential rotation, request limits, quota, retention and production authorization.
172
+
173
+ Full UI views include questions, brief, harness/cost/setup, allowance, progress,
174
+ bounded logs, artifact IDs/hashes, source snapshots, PR URLs and supported controls.
175
+ They remove configured private path prefixes and redact resolved secrets;
176
+ repository-relative artifact paths remain available in authorized UI views.
177
+ Model output includes bounded capability discovery, task/revision/status,
178
+ repository/harness identity, completion, question IDs and text, supported controls,
179
+ blocked-task recovery guidance and the PR link. List pages include question counts;
180
+ inspect and mutation responses include the questions. Raw logs and brief bytes
181
+ stay in UI metadata. Artifact download authorization/storage remains APort's
182
+ job; the public dispatcher exposes stable manifests, not arbitrary file retrieval.
183
+
184
+ `uiResourceConfiguration` accepts the single registered `ui://` URI, dedicated
185
+ HTTPS origin and exact CSP connect/resource origins. Global sidebar and thread
186
+ panel entrypoints share it. HTML is supplied from the built APort UI (2,000,000 bytes
187
+ maximum, shared by the package builder and runtime reader), served as
188
+ `text/html;profile=mcp-app`. Fixture HTML proves resource
189
+ wiring only. No final UI or host availability is claimed here.
190
+
191
+ ## Runtime and existing Pages deployment
192
+
193
+ Node 22 is the supported workflow runtime. Inject `ctx.state`, `gh`, `git`,
194
+ `credential`, `identity`, `notify`, `executionFor`, source/brief storage and clock
195
+ using the predecessor context contracts. The runtime calls `makeTick` for all
196
+ review decisions. Durable home stores registry, tasks, briefs, provider intent,
197
+ events and artifacts; neither container disk nor Pages temporary files suffice.
198
+ Bounded entry/chain batches run on each externally scheduled wake. Active chains
199
+ rotate by a persisted name cursor; done, cancelled and stopped history consumes
200
+ no batch slots. Completion or cancellation cannot shift the remaining window.
201
+ `maxChains: 0` explicitly disables chain processing for that coordinator. Entry
202
+ and chain cursors commit only after a successful tick. The canonical tick's chain
203
+ poll deadline is persisted too: pending batches finish their sweep, then chain
204
+ reads wait for `poll_seconds` even across process restarts. Faster wakes continue
205
+ entry/provider reconciliation without advancing the chain cursor. The next wake
206
+ is scheduled before reconciliation, so a crash cannot lose recovery scheduling.
207
+
208
+ `createNodeOwnerStore({home,durable:true,replicas:1})` uses the existing daemon
209
+ exclusion plus persisted monotonic fence/instance. It cannot expire a live owner;
210
+ the stale-process check recovers after eviction. A UI or repeated callback never
211
+ creates a concurrent owner. Do not share this lock across hosts or advertise it as
212
+ a distributed lease. Injected distributed stores must atomically enforce fencing
213
+ at their write boundaries. The wrapper guards context effects and retains provider
214
+ dispatch ambiguity through the existing execution service.
215
+
216
+ Before wake-up, migrate/pin the exact runtime artifact. Supply the emitted
217
+ `runtime.json` to `createNodeCoordinator({ctx,store,schedule,manifest})`.
218
+ The coordinator refuses a different active-job digest. Compatible patches keep
219
+ task/provider/brief identities; drain jobs before staging a different artifact.
220
+ No running code is silently upgraded. The public API's pre-1.0 compatibility
221
+ window is `0.2.x`, with operation/task/execution wire schemas all `1`; other
222
+ versions need migration.
223
+
224
+ The portable contracts/views/wake envelope have no Node dependencies. The complete
225
+ task service and both transport implementations still require Node filesystem,
226
+ child processes, Git/gh and isolated verification. `npm test` bundles the portable
227
+ entries for browsers and checks their shared liveness predicates. The installed
228
+ artifact check (`test:plugin-package`) repeats those bundles and confirms the full
229
+ Node runtime rejects a browser target, separately from actual Node execution. This
230
+ is **not** a tested Workers-native workflow runtime or deployed Pages endpoint.
231
+ The smallest remedy: keep existing Pages OAuth/MCP/UI; connect its authenticated
232
+ runtime binding to one Node 22 coordinator with a durable volume and external
233
+ wake-ups. Evaluate an already supported Node runtime or Cloudflare Container in
234
+ the existing account before provisioning. No mandatory new Worker/VPS is proposed.
235
+
236
+ Cloud additionally needs the pinned Codex CLI and trusted operator sign-in. Its
237
+ predecessor currently blocks new dispatch until a documented environment-to-repo
238
+ check can be implemented/qualified. Preserve that block; native Cloud HTTP,
239
+ public credential delegation, cancellation and interrupt are not invented.
240
+ Agents API credentials, exact model/environment access and inference/compute
241
+ allowance must be supplied by the authorized account; no subscription entitlement
242
+ is inferred. Both transports remain exported and covered by installed fixtures.
243
+
244
+ The current registry declares bounded natural-language preparation for
245
+ `openai-agents`: `agents-text-only-v1`, authority `text-only`, environment `none`.
246
+ Its creation request disables tools and delegation; effective session and output
247
+ checks enforce that boundary. Claude and Codex have their own registered local
248
+ preparation boundaries. Codex Cloud, Gemini, OpenCode and Goose expose
249
+ `canPrepare:false` with a remedy; selecting them for preparation cannot silently
250
+ fall back to another provider or gain implementation authority.
251
+
252
+ Capability responses describe this implementation, not account entitlement or a
253
+ completed live workflow. Installed fixtures cover shared API/Cloud transport,
254
+ recovery and publication; preparation qualification and live account prerequisites
255
+ remain explicit in [preparation](preparation.md), [Agents setup](openai-agents.md)
256
+ and [Cloud availability](codex-cloud.md). The package can be integrated through
257
+ MCP or the scoped operation API, but is not itself a deployed multi-tenant service.
258
+
259
+ ## Build, configure, upgrade and rollback
260
+
261
+ Build from the same tagged/merged source and explicit core version. Commit or
262
+ remove npm ignore/configuration controls before a public build, including ignored
263
+ controls or directories under the runtime payload. Internal builds record these
264
+ changes and remain development fixtures:
265
+
266
+ ```sh
267
+ npm ci --ignore-scripts
268
+ node bin/package-plugin.mjs --config /private/aport-package.json --validate-public
269
+ npm run package:plugin -- --config /private/aport-package.json --out /private/candidate \
270
+ --core-version 0.2.0 --source-commit <40-character-merged-commit>
271
+ # For development only, add --internal; keep fixture:true in the config.
272
+ npm install --ignore-scripts --prefix /private/candidate-runtime /private/candidate/uchibeke-gallivant-0.2.0.tgz
273
+ node /private/candidate-runtime/node_modules/@uchibeke/gallivant/bin/task-delivery-state.mjs check \
274
+ --home /durable/preview --manifest /private/candidate/runtime.json
275
+ node /private/previous-runtime/node_modules/@uchibeke/gallivant/bin/task-delivery-state.mjs backup \
276
+ --home /durable/preview --manifest /private/previous/runtime.json --out /private/backup
277
+ node /private/candidate-runtime/node_modules/@uchibeke/gallivant/bin/task-delivery-state.mjs migrate \
278
+ --home /durable/preview --manifest /private/candidate/runtime.json
279
+ # Roll back package AND state into a fresh namespace, then switch the existing binding.
280
+ npm install --ignore-scripts --prefix /private/previous-runtime /private/previous/uchibeke-gallivant-0.2.0.tgz
281
+ node /private/previous-runtime/node_modules/@uchibeke/gallivant/bin/task-delivery-state.mjs rollback \
282
+ --backup /private/backup --out /durable/restored --manifest /private/previous/runtime.json
283
+ npm run test:plugin-package
284
+ ```
285
+
286
+ Replace the illustrative `/private/...` and `/durable/...` paths with private,
287
+ writable locations on your host. The upgrade example assumes the previous
288
+ package is installed under `/private/previous-runtime`; use that installed
289
+ artifact for backup. First-time setup has no previous namespace to back up.
290
+ Separate installation prefixes keep candidate and rollback versions out of the
291
+ source checkout and avoid depending on a global executable or shell `PATH`.
292
+
293
+ Stop new intake/wake-ups and the old coordinator before backup/migration. Active
294
+ jobs retain their runtime; incompatible changes fail with this remedy. Backups
295
+ are private, outside public packages, omit operator config/auth, and preserve
296
+ task/run/provider/source identities. Back up with the currently pinned, pre-upgrade
297
+ manifest; a candidate manifest cannot label an older namespace's backup. Restore
298
+ requires both the backup envelope and copied runtime pin to match the selected
299
+ artifact. Unpinned legacy state can be backed up with an explicit compatible
300
+ manifest and must be migrated before enabling its coordinator.
301
+ Verify store consistency before switching bindings. Keep old runtime artifacts
302
+ and credential bindings available for rollback; do not merge/upgrade live jobs.
303
+
304
+ A qualified `delivery_ready` handoff releases its runtime pin even while its
305
+ retained registry state is `ready-for-human`. Pending controls, live or uncollected
306
+ execution, unresolved intake/receipts and active chains still prevent migration.
307
+ Pending learning delivery audits also retain the pin and keep coordinator wake-ups
308
+ active. They retry separately after handoff without polling the settled provider,
309
+ reopening PR review or launching another agent turn; a successful audit drains
310
+ the saved outbox and releases that remaining work.
311
+ Legacy tasks, `integrated` tasks awaiting merge and unresolved `needs-human` work
312
+ retain their pins; the scheduling pause alone does not make a namespace idle.
313
+
314
+ Package config supplies publisher `APort`, exact endpoint, `resource` configuration,
315
+ owner-selected support email/product/support/privacy/terms/license URLs and explicit
316
+ asset paths (`assets.ui`, `assets.icon`, `assets.screenshots`). The emitted combined
317
+ skills/MCP ZIP has one HTTPS MCP server, Apache-2.0 license and explicit assets.
318
+ Runtime tarball, recipe, operation schemas and manifest record source commit,
319
+ core/contracts, dependency lock, payload/asset/schema hashes and artifact SHA-256.
320
+ The published runtime carries `npm-shrinkwrap.json`, so the installed builder
321
+ uses the same dependency lock as the source build.
322
+ No credential headers or unrelated tree files enter the plugin. Keep input config,
323
+ private backups, provider logs and reviewer credentials outside the output.
324
+
325
+ Public packaging also requires `oauth`, `review`, and `publication`. The OAuth
326
+ input deliberately matches APort's currently implemented registered public client:
327
+ `type: "oauth"`, `client: { mode: "provided", clientId: "<registered ID>",
328
+ tokenEndpointAuthMethod: "none" }`, and `baseScopes` copied from the public
329
+ authorization server's actual discovery/tool contract. APort's public scopes are
330
+ `tasks:read`, `tasks:write`, `tasks:check`, and `tasks:control`; they are distinct
331
+ from Gallivant's internal delivery scopes. The builder validates OAuth scope-token
332
+ syntax and preserves the deployment's supplied values without translating them.
333
+ Verify exact agreement with live discovery before connecting. Optional `authorizationUrl` and
334
+ `tokenUrl` override discovery. Register the exact redirect URI displayed by the
335
+ host's MCP management page in APort's `TASK_DELIVERY_CLIENTS`; do not assume the
336
+ GitHub login callback is the host callback. No client secret belongs in this
337
+ public PKCE configuration. DCR/CIMD and confidential clients are not implemented
338
+ by this APort deployment and are not accepted by its packager.
339
+
340
+ Optional `oauth.defaultScopes` uses the same token validation as `baseScopes`,
341
+ but permits an empty array. Per OpenAI's OAuth configuration reference, `[]`
342
+ suppresses client/server default scopes; omitting it preserves those defaults.
343
+ `baseScopes` remains mandatory and is included in every authorization request.
344
+ Use the explicit empty override when all requested scopes are supplied there;
345
+ verify the actual host authorization request after updating its package.
346
+
347
+ `review.test_cases` must contain exactly five `positive` and three `negative`
348
+ cases. Every case needs `description` and `prompt`; positive cases also need
349
+ `tools_triggered` (comma-separated actual `task_*` names) and
350
+ `expected_behavior`. Optional `file_attachment_urls` and `expected_output_url`
351
+ must be public HTTPS URLs. `review.demo_recording_url` must identify the actual
352
+ accessible walkthrough; it may include a video query string. Supply
353
+ `publication.release_notes`. The builder emits review beside `interface` under
354
+ `extensions.com.openai`, and auth under the MCP server's
355
+ `extensions.com.openai.auth`. Missing fields stop public preflight. Internal
356
+ fixtures may omit the three inputs; supplied inputs are still validated. A
357
+ correct metadata shape does not prove its cases ran or qualify the release.
358
+
359
+ Optional `listing: { longDescription, category }` replaces those two directory
360
+ fields through the same builder. Describe the intended users and actual access
361
+ limitations; use an exact category title from the publisher dashboard (for this
362
+ repository workflow, `Developer Tools`). Descriptions allow up to 4000 characters
363
+ and line breaks. Category titles must be one line of at most 80 characters.
364
+ Unknown fields, credentials, blank values and unsupported controls are rejected.
365
+ Identity, publisher, review inputs and release gates cannot be overridden here.
366
+ Keep final listing copy in the package config rather than editing a generated ZIP.
367
+ See [OpenAI listing metadata](https://developers.openai.com/plugins/deploy/submission#listing-metadata).
368
+
369
+ For a disposable sandbox portal draft, internal builds can set
370
+ `developmentIdentity: { name: "aport-task-delivery-preview", displayName:
371
+ "APort Tasks Preview" }`. This prevents a sandbox connection from occupying the
372
+ canonical directory identity: changing a registered MCP server URL later is not
373
+ a self-service update. Public validation refuses this input; use the canonical
374
+ identity and permanent production endpoint for the actual release.
375
+
376
+ The vendored portable MCP schema predates this OpenAI authentication extension.
377
+ Validation retains the original schema bytes and adds only the documented,
378
+ strictly validated auth overlay. The release manifest records its separate
379
+ `submissionSchemaSha256`. Do not hand-edit the emitted ZIP to add metadata or
380
+ weaken the portable schema to admit arbitrary server fields. Reviewer credentials
381
+ and private reviewer instructions are rejected; enter them only in the portal.
382
+
383
+ The configuration shape is:
384
+
385
+ ```json
386
+ {
387
+ "publisher": "APort",
388
+ "endpoint": "https://aport.io/api/task-delivery/mcp",
389
+ "fixture": false,
390
+ "supportEmail": "<owner-selected support email>",
391
+ "homepage": "<owner-selected HTTPS product URL>",
392
+ "supportUrl": "<owner-selected HTTPS support URL>",
393
+ "privacyUrl": "<owner-selected HTTPS privacy URL>",
394
+ "termsUrl": "<owner-selected HTTPS terms URL>",
395
+ "licenseUrl": "<owner-selected HTTPS license URL>",
396
+ "resource": {
397
+ "uri": "ui://task-delivery/app",
398
+ "domain": "https://aport.io",
399
+ "connectDomains": ["https://aport.io"],
400
+ "resourceDomains": []
401
+ },
402
+ "assets": {
403
+ "ui": "/private/aport-ui/task-delivery.html",
404
+ "icon": "/private/aport-ui/icon.png",
405
+ "screenshots": ["/private/aport-ui/actual-host.png"]
406
+ }
407
+ }
408
+ ```
409
+
410
+ Replace every placeholder and bind the actual built UI's exact origins. This
411
+ shape alone does not prove deployment or supply final assets. Public packaging
412
+ also requires a clean source payload and verifies the requested source commit
413
+ against HEAD. Internal dirty builds record their changed payload files and hashes.
414
+
415
+ Public validation refuses absent metadata, example URLs, unavailable built UI,
416
+ fixture assets and missing screenshots with remedies. A structurally valid
417
+ package remains `public-candidate-unqualified`, never submission-ready by itself.
418
+ Rebuild executable/configuration changes and invalidate affected evidence.
419
+
420
+ Official formats rechecked 2026-10-12: [portable packaging](https://developers.openai.com/plugins/build/plugins),
421
+ [UI resources](https://developers.openai.com/plugins/build/chatgpt-ui),
422
+ [global/thread entrypoints](https://developers.openai.com/plugins/build/extensions),
423
+ [submission](https://developers.openai.com/plugins/deploy/submission).
424
+ Vendored portable JSON schemas retain their source URLs and recorded hashes.
425
+
426
+ ## APort reference integration: M6 handoff gates
427
+
428
+ These gates belong to the APort integration handoff. M5 artifact tests are
429
+ deterministic and unpaid; they are not actual host evidence.
430
+ M6 pins the **human-merged** artifact/digest into the existing APort job, verifies
431
+ real Pages/runtime/bindings/durable storage, and reconciles PR #414's deployment.
432
+ The 2026-10-07 endpoint probe returned HTTP 503. That audit session had no configured
433
+ Agents API credential/model/environment; pinned Cloud listing was accessible but
434
+ proved neither environment repository nor inference access. Browser/capture
435
+ inventory was available, with no task-delivery tool installed in that session.
436
+
437
+ Mandatory remaining gates: actual endpoint OAuth discovery/tool scans and scoped
438
+ account isolation; both providers' real implementation and correction PRs across
439
+ restart; public Cloud mode only if delegation is demonstrated (otherwise trusted
440
+ operator mode); actual sidebar/panel and fresh-account reconnect; restricted
441
+ reviewer account with shared campaign allowance; authentic screenshots/demo;
442
+ working legal/support pages; eligible publisher project/org/domain verification;
443
+ bounded G9 kit with five positive/three negative cases. APort is publisher. No
444
+ release approval, submission, deployment or publication is claimed by M5.
445
+
446
+ ### Model-visible discovery and evidence
447
+
448
+ `list` accepts an optional saved task ID as `cursor`, returns at most 100 authorized
449
+ tasks in ID order, and supplies `nextCursor` when `truncated` is true. Every page
450
+ uses current account and repository authorization; a cursor grants no access.
451
+ MCP evidence responses expose bounded artifact IDs/hashes, provider test claims,
452
+ coordinator verification observations and the PR link. Log responses expose the
453
+ saved window range, count, gap and `nextAfter`, while raw log text and briefs remain
454
+ in authorized UI metadata. Neither read operation starts provider reconciliation.
455
+
456
+
457
+ CLI task mutations serialize with runtime backup and migration using the task mutation owner, while ordinary daemon operation remains available. A namespace containing `runtime-pin.json` requires the manifest-aware delivery adapter for writes; the CLI can still list and inspect it. Keep ordinary CLI tasks in an unpinned local home. Package output directories must be outside the package source root, including destinations reached through symlinked parents.
458
+
459
+
460
+ First-time runtime pinning requires an idle legacy namespace; retain the original runtime until active intake and execution are drained. All CLI registry mutations, chain writes and control requests share maintenance exclusion, including local web control requests. Pinned namespaces require the manifest-aware adapter.
461
+
462
+ The filesystem delivery adapter admits at most 256 ordinary operation identities per account scope and caps their serialized store section at 32 MiB. At the operation-count limit, retained operation IDs remain available for idempotent retries; new ordinary operations fail with `DELIVERY_CAPACITY` before task effects. Keep old namespaces for retries, drain their active work and archive them before provisioning a separate namespace for new work. Never route retries to a new namespace or delete receipts to free capacity. A size-limit failure during acknowledgement preserves the durable intent; inspect and reconcile that operation before authorizing another identity. Oversized legacy stores require an operator-managed archival/indexed-store migration that preserves identities; files exceeding the combined byte ceiling are refused before loading into memory.
463
+
464
+ Cancellation uses a separate 1 MiB reserve of at most 256 compact receipts, one per retained task. Ordinary receipts retain their 256-ID and 32 MiB limits. Cancel retries retain the original operation ID and signature, reauthorize, and return the current task view; they do not retain another full snapshot. A new cancellation identity for an already reserved task is refused with instructions to retry its original ID or inspect its status. This reserve cannot be consumed by other controls, and lost scheduling acknowledgements remain retryable without repeating cancellation effects.
465
+
466
+ New ordinary receipts reserve 4 KiB for the compact acknowledgement and bounded task/repository binding before any task effects. Acknowledgements retain operation signatures and task identity, not full task-view snapshots; retries reauthorize and return the current task view without repeating effects. Historical acknowledged snapshots remain replayable. Historical pending intents must pass the same reservation check before recovery. List model responses contain task/repository identity, status and question count; inspect and mutation responses retain question text.
467
+
468
+ Interrupted resume, validation and start requests whose intake revision has advanced are settled from the current saved task view, including blocked or incomplete outcomes. Exact retries do not repeat their effects or infer approval from a later revision. Further recovery requires inspection and a new operation against that revision; unresolved intake or execution state continues to pin its artifact independently of the settled delivery receipt.
469
+
470
+ Public packaging rechecks HEAD and payload changes after npm packing. A changed checkout or failed Git recheck removes the staged output and requires a rebuild; internal fixtures record late payload changes or loss of source verification without claiming release qualification.
471
+
472
+ Archive payload hashes are computed from packed entries and checked against the selected Git commit. The bundled parser is bound by `templates/plugin/bundled-runtime.json`, whose file hashes and lock integrity must be refreshed and committed together when upgrading that dependency. Before/after Git status remains an additional check, not byte provenance.
473
+
474
+ New delivery intents fence later ordinary mutations until the original operation settles; cancellation retains its independent reserve. This prevents unrelated revision changes from being accepted as an interrupted operation's outcome. Legacy intents without this fence cannot use revision-only recovery and remain explicit reconciliation obligations.
475
+
476
+ Explicit task-service refusals proven to precede effects are stored as compact acknowledged rejection receipts. Exact retries replay the bounded redacted code/message; corrected requests use a new identity and current revision. Unknown failures keep their intent and mutation fence rather than being classified as safe from an unchanged revision alone.