@defrex/autobuild 0.8.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 (251) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +192 -0
  3. package/SPEC.md +2269 -0
  4. package/bin/ab-build-runner.ts +47 -0
  5. package/bin/ab-dev.ts +27 -0
  6. package/bin/ab-dispatch-kernel.ts +92 -0
  7. package/bin/ab-harvest-runner.ts +29 -0
  8. package/bin/ab-init-probe.ts +19 -0
  9. package/bin/ab-process-group-reaper.ts +32 -0
  10. package/bin/ab.ts +6 -0
  11. package/bin/agent/ab +3 -0
  12. package/docs/answering-blocked-builds.md +89 -0
  13. package/docs/architecture.md +726 -0
  14. package/docs/assets/headline-wide.png +0 -0
  15. package/docs/configuration.md +1623 -0
  16. package/docs/hosted-dispatcher-cutover-validation.md +178 -0
  17. package/docs/hosted-dispatcher.md +204 -0
  18. package/docs/mcp.md +119 -0
  19. package/docs/operator-api.md +186 -0
  20. package/docs/remote-store-protocol.md +972 -0
  21. package/docs/remote-ticket-protocol.md +79 -0
  22. package/docs/setup.md +289 -0
  23. package/docs/spec-standard.md +63 -0
  24. package/docs/ticket-dependencies.md +59 -0
  25. package/docs/vercel-sandbox-rollout-probe.md +7 -0
  26. package/package.json +135 -0
  27. package/packages/core/src/cli/args.ts +74 -0
  28. package/packages/core/src/cli/artifact.ts +182 -0
  29. package/packages/core/src/cli/binary.ts +198 -0
  30. package/packages/core/src/cli/build-control.ts +789 -0
  31. package/packages/core/src/cli/build-progress.ts +55 -0
  32. package/packages/core/src/cli/bulk-control.ts +385 -0
  33. package/packages/core/src/cli/context.ts +470 -0
  34. package/packages/core/src/cli/dashboard/actions.ts +59 -0
  35. package/packages/core/src/cli/dashboard/cells.ts +92 -0
  36. package/packages/core/src/cli/dashboard/composer.ts +230 -0
  37. package/packages/core/src/cli/dashboard/detail.ts +100 -0
  38. package/packages/core/src/cli/dashboard/frame-image.ts +373 -0
  39. package/packages/core/src/cli/dashboard/live.ts +152 -0
  40. package/packages/core/src/cli/dashboard/model.ts +1173 -0
  41. package/packages/core/src/cli/dashboard/poll.ts +196 -0
  42. package/packages/core/src/cli/dashboard/render.ts +1568 -0
  43. package/packages/core/src/cli/dashboard/selection.ts +66 -0
  44. package/packages/core/src/cli/dashboard/session-feed.ts +244 -0
  45. package/packages/core/src/cli/dashboard/session-view.ts +506 -0
  46. package/packages/core/src/cli/dashboard/transcript.ts +108 -0
  47. package/packages/core/src/cli/dev.ts +46 -0
  48. package/packages/core/src/cli/dispatch-frontend.ts +1045 -0
  49. package/packages/core/src/cli/dispatch-process.ts +259 -0
  50. package/packages/core/src/cli/dispatch.ts +3692 -0
  51. package/packages/core/src/cli/dotenv.ts +48 -0
  52. package/packages/core/src/cli/env.ts +206 -0
  53. package/packages/core/src/cli/harvest.ts +698 -0
  54. package/packages/core/src/cli/help.ts +713 -0
  55. package/packages/core/src/cli/init-agent.ts +106 -0
  56. package/packages/core/src/cli/init-validation.ts +583 -0
  57. package/packages/core/src/cli/init.ts +756 -0
  58. package/packages/core/src/cli/installation.ts +333 -0
  59. package/packages/core/src/cli/keyboard.ts +261 -0
  60. package/packages/core/src/cli/main.ts +1399 -0
  61. package/packages/core/src/cli/mcp.ts +279 -0
  62. package/packages/core/src/cli/models.ts +65 -0
  63. package/packages/core/src/cli/observe.ts +55 -0
  64. package/packages/core/src/cli/plugin.ts +227 -0
  65. package/packages/core/src/cli/pr-attachments.ts +138 -0
  66. package/packages/core/src/cli/pr-summary.ts +124 -0
  67. package/packages/core/src/cli/publication-settlement.ts +188 -0
  68. package/packages/core/src/cli/repo-state.ts +213 -0
  69. package/packages/core/src/cli/repository-status.ts +80 -0
  70. package/packages/core/src/cli/self-update.ts +443 -0
  71. package/packages/core/src/cli/status.ts +895 -0
  72. package/packages/core/src/cli/store-opening.contract.ts +289 -0
  73. package/packages/core/src/cli/store-opening.ts +167 -0
  74. package/packages/core/src/cli/store-ref.ts +33 -0
  75. package/packages/core/src/cli/terminal-restore.ts +174 -0
  76. package/packages/core/src/cli/terminal.ts +361 -0
  77. package/packages/core/src/cli/terminals.ts +995 -0
  78. package/packages/core/src/cli/testkit.ts +194 -0
  79. package/packages/core/src/cli/ticket.ts +484 -0
  80. package/packages/core/src/cli/upgrade-agent.ts +180 -0
  81. package/packages/core/src/cli/upgrade-commit.ts +468 -0
  82. package/packages/core/src/cli/upgrade-notice.ts +91 -0
  83. package/packages/core/src/cli/upgrade-progress.ts +110 -0
  84. package/packages/core/src/cli/upgrade.ts +888 -0
  85. package/packages/core/src/cli/wait.ts +587 -0
  86. package/packages/core/src/cli/watch.ts +932 -0
  87. package/packages/core/src/config/live.ts +255 -0
  88. package/packages/core/src/config/load.ts +98 -0
  89. package/packages/core/src/config/roles.ts +438 -0
  90. package/packages/core/src/config/schema.ts +774 -0
  91. package/packages/core/src/distribution.ts +24 -0
  92. package/packages/core/src/events/catalog.ts +201 -0
  93. package/packages/core/src/events/envelope.ts +59 -0
  94. package/packages/core/src/events/payloads.ts +618 -0
  95. package/packages/core/src/events/repository.ts +559 -0
  96. package/packages/core/src/events/sessions.ts +180 -0
  97. package/packages/core/src/harvest/schema.ts +147 -0
  98. package/packages/core/src/ids.ts +45 -0
  99. package/packages/core/src/integration/harness.ts +681 -0
  100. package/packages/core/src/kernel/auto-merge.ts +259 -0
  101. package/packages/core/src/kernel/converge.ts +117 -0
  102. package/packages/core/src/kernel/dispatch-settings.ts +60 -0
  103. package/packages/core/src/kernel/dispatch-status.ts +141 -0
  104. package/packages/core/src/kernel/engine.ts +1047 -0
  105. package/packages/core/src/kernel/harvest.ts +823 -0
  106. package/packages/core/src/kernel/origin.ts +69 -0
  107. package/packages/core/src/kernel/phases.ts +196 -0
  108. package/packages/core/src/kernel/plan-verify-selection.ts +105 -0
  109. package/packages/core/src/kernel/pr-attachments.ts +82 -0
  110. package/packages/core/src/kernel/reducer.ts +752 -0
  111. package/packages/core/src/kernel/stall.ts +155 -0
  112. package/packages/core/src/kernel/verify-applicability.ts +52 -0
  113. package/packages/core/src/markdown.ts +67 -0
  114. package/packages/core/src/ontology.ts +288 -0
  115. package/packages/core/src/open-map.ts +203 -0
  116. package/packages/core/src/operator/annotations.ts +187 -0
  117. package/packages/core/src/operator/client.ts +311 -0
  118. package/packages/core/src/operator/control.ts +117 -0
  119. package/packages/core/src/operator/index.ts +62 -0
  120. package/packages/core/src/operator/presentation.ts +22 -0
  121. package/packages/core/src/operator/protocol.ts +98 -0
  122. package/packages/core/src/operator/query.ts +201 -0
  123. package/packages/core/src/operator/registry.ts +1043 -0
  124. package/packages/core/src/operator/requests.ts +138 -0
  125. package/packages/core/src/operator/sandbox.ts +458 -0
  126. package/packages/core/src/operator/server.ts +616 -0
  127. package/packages/core/src/operator/sessions.ts +223 -0
  128. package/packages/core/src/operator/tickets.ts +177 -0
  129. package/packages/core/src/plugin-sdk/index.ts +174 -0
  130. package/packages/core/src/plugins/contract-entry.ts +74 -0
  131. package/packages/core/src/plugins/contract-env.ts +3 -0
  132. package/packages/core/src/plugins/load.ts +259 -0
  133. package/packages/core/src/plugins/manifest.ts +236 -0
  134. package/packages/core/src/plugins/registry.ts +274 -0
  135. package/packages/core/src/plugins/runtimes.ts +75 -0
  136. package/packages/core/src/ports/forge/contract.ts +258 -0
  137. package/packages/core/src/ports/forge/create.ts +74 -0
  138. package/packages/core/src/ports/forge/fake.ts +488 -0
  139. package/packages/core/src/ports/forge/github-pr-attachments.ts +351 -0
  140. package/packages/core/src/ports/forge/github-transport.ts +352 -0
  141. package/packages/core/src/ports/forge/github.ts +1162 -0
  142. package/packages/core/src/ports/forge/local-git.ts +568 -0
  143. package/packages/core/src/ports/runner/claude.ts +873 -0
  144. package/packages/core/src/ports/runner/cli-stream.ts +90 -0
  145. package/packages/core/src/ports/runner/codex.ts +873 -0
  146. package/packages/core/src/ports/runner/contract.ts +492 -0
  147. package/packages/core/src/ports/runner/fake.ts +213 -0
  148. package/packages/core/src/ports/runner/json-record.ts +2 -0
  149. package/packages/core/src/ports/runner/live-contract-fixture.ts +176 -0
  150. package/packages/core/src/ports/runner/one-shot.ts +29 -0
  151. package/packages/core/src/ports/runner/pi-bridge-core.ts +136 -0
  152. package/packages/core/src/ports/runner/pi-bridge.js +6 -0
  153. package/packages/core/src/ports/runner/pi-rpc.ts +454 -0
  154. package/packages/core/src/ports/runner/pi.ts +617 -0
  155. package/packages/core/src/ports/runner/production.ts +74 -0
  156. package/packages/core/src/ports/runner/provider-error.ts +121 -0
  157. package/packages/core/src/ports/runner/routing.ts +234 -0
  158. package/packages/core/src/ports/runner/runtime.ts +214 -0
  159. package/packages/core/src/ports/runner/session-env.ts +34 -0
  160. package/packages/core/src/ports/runner/stream-parts.ts +103 -0
  161. package/packages/core/src/ports/tickets/contract.ts +570 -0
  162. package/packages/core/src/ports/tickets/create.ts +135 -0
  163. package/packages/core/src/ports/tickets/fake.ts +215 -0
  164. package/packages/core/src/ports/tickets/file.ts +559 -0
  165. package/packages/core/src/ports/tickets/linear.ts +811 -0
  166. package/packages/core/src/ports/tickets/operations.ts +161 -0
  167. package/packages/core/src/ports/tickets/remote-index.ts +13 -0
  168. package/packages/core/src/ports/tickets/remote-protocol.ts +80 -0
  169. package/packages/core/src/ports/tickets/remote-server.ts +185 -0
  170. package/packages/core/src/ports/tickets/remote.ts +130 -0
  171. package/packages/core/src/ports/tickets/update.ts +51 -0
  172. package/packages/core/src/ports/types.ts +528 -0
  173. package/packages/core/src/ports/workspace/build-execution.ts +123 -0
  174. package/packages/core/src/ports/workspace/contract.ts +136 -0
  175. package/packages/core/src/ports/workspace/create.ts +132 -0
  176. package/packages/core/src/ports/workspace/distribution-archive.ts +317 -0
  177. package/packages/core/src/ports/workspace/fake.ts +432 -0
  178. package/packages/core/src/ports/workspace/git-worktree.ts +848 -0
  179. package/packages/core/src/ports/workspace/harvest-execution.ts +111 -0
  180. package/packages/core/src/ports/workspace/in-process-build-execution.ts +30 -0
  181. package/packages/core/src/ports/workspace/local-build-execution.ts +88 -0
  182. package/packages/core/src/ports/workspace/operator-sandbox.ts +142 -0
  183. package/packages/core/src/ports/workspace/phase-scratch.ts +156 -0
  184. package/packages/core/src/ports/workspace/vercel-sandbox.ts +2541 -0
  185. package/packages/core/src/processes/build-child-exit.ts +78 -0
  186. package/packages/core/src/processes/build-child.ts +119 -0
  187. package/packages/core/src/processes/build-execution-state.ts +95 -0
  188. package/packages/core/src/processes/build-parent-watch.ts +35 -0
  189. package/packages/core/src/processes/build-runner.ts +2614 -0
  190. package/packages/core/src/processes/dispatcher.ts +2825 -0
  191. package/packages/core/src/processes/execution-settlement.ts +171 -0
  192. package/packages/core/src/processes/harvest-child.ts +115 -0
  193. package/packages/core/src/processes/harvest-execution-state.ts +121 -0
  194. package/packages/core/src/processes/harvest-runner.ts +1656 -0
  195. package/packages/core/src/processes/harvest.ts +595 -0
  196. package/packages/core/src/processes/infrastructure-failure-budget.ts +146 -0
  197. package/packages/core/src/processes/phase-failure-budget.ts +52 -0
  198. package/packages/core/src/processes/process-group-reaper.ts +35 -0
  199. package/packages/core/src/processes/process-group.ts +65 -0
  200. package/packages/core/src/processes/publication-loss.ts +62 -0
  201. package/packages/core/src/processes/publication-state.ts +93 -0
  202. package/packages/core/src/processes/sandbox-state.ts +101 -0
  203. package/packages/core/src/registry.ts +24 -0
  204. package/packages/core/src/sessions/reducer.ts +185 -0
  205. package/packages/core/src/skills.ts +7 -0
  206. package/packages/core/src/spec-standard.ts +47 -0
  207. package/packages/core/src/store/adapter.ts +80 -0
  208. package/packages/core/src/store/build-scope.ts +272 -0
  209. package/packages/core/src/store/contract.ts +2581 -0
  210. package/packages/core/src/store/local/blobs.ts +38 -0
  211. package/packages/core/src/store/local/schema.ts +180 -0
  212. package/packages/core/src/store/local/store.ts +1713 -0
  213. package/packages/core/src/store/memory.ts +1138 -0
  214. package/packages/core/src/store/phase-session.ts +425 -0
  215. package/packages/core/src/store/remote/client.ts +780 -0
  216. package/packages/core/src/store/remote/index.ts +12 -0
  217. package/packages/core/src/store/remote/protocol.ts +348 -0
  218. package/packages/core/src/store/remote/server.ts +923 -0
  219. package/packages/core/src/store/remote/token.ts +137 -0
  220. package/packages/core/src/store/remote/version.ts +10 -0
  221. package/packages/core/src/store/retention.ts +91 -0
  222. package/packages/core/src/store/session-handle.ts +265 -0
  223. package/packages/core/src/store/streams/assemble.ts +79 -0
  224. package/packages/core/src/store/streams/lock.ts +42 -0
  225. package/packages/core/src/store/streams/session-writer.ts +306 -0
  226. package/packages/core/src/store/streams/types.ts +171 -0
  227. package/packages/core/src/store/streams/wait.ts +127 -0
  228. package/packages/core/src/store/subscribe.ts +105 -0
  229. package/packages/core/src/store/types.ts +466 -0
  230. package/packages/core/src/testing/fixed.ts +44 -0
  231. package/packages/core/src/testing/store-failures.ts +32 -0
  232. package/packages/core/src/zod-issues.ts +91 -0
  233. package/skills/code-review/SKILL.md +100 -0
  234. package/skills/finalize/SKILL.md +44 -0
  235. package/skills/guide/SKILL.md +1781 -0
  236. package/skills/guide/references/operator-api.md +164 -0
  237. package/skills/guide/references/plugin-authoring.md +354 -0
  238. package/skills/guide/references/remote-store-protocol.md +972 -0
  239. package/skills/guide/references/remote-ticket-protocol.md +79 -0
  240. package/skills/guide/references/setup.md +289 -0
  241. package/skills/guide/references/spec-standard.md +63 -0
  242. package/skills/guide/references/ticket-dependencies.md +59 -0
  243. package/skills/harvest/SKILL.md +66 -0
  244. package/skills/harvest-review/SKILL.md +63 -0
  245. package/skills/implement/SKILL.md +82 -0
  246. package/skills/plan/SKILL.md +123 -0
  247. package/skills/plan-review/SKILL.md +121 -0
  248. package/skills/reconcile/SKILL.md +65 -0
  249. package/skills/spec/SKILL.md +132 -0
  250. package/skills/tickets/SKILL.md +139 -0
  251. package/templates/autobuild.toml +36 -0
@@ -0,0 +1,186 @@
1
+ # Operator API v1
2
+
3
+ The hosted service exposes the polling-oriented operator surface at
4
+ `/operator/v1/repos/{repo}`. It is versioned with remote store protocol **2**.
5
+ Every request must send `X-Autobuild-Version`,
6
+ `X-Autobuild-Protocol-Version: 2`, and `Authorization: Bearer …`. Identity is
7
+ checked before authentication or resource lookup.
8
+
9
+ Mint a token offline; the signed user is used as the human actor on every write:
10
+
11
+ ```sh
12
+ AB_STORE_SECRET='…' bun packages/hosted-store-service/src/bin.ts mint operator \
13
+ --user 'Ada Lovelace' --ttl-seconds 3600
14
+ ```
15
+
16
+ Admin, build, repository, and deployment (`{ "operator": true, … }`) tokens
17
+ have no attributed operator authority. Human-operator tokens have no raw
18
+ `/builds`, `/repos`, `/sessions`, or `/tickets` authority. Encode repository,
19
+ build, session, and artifact kind as separate URL path segments.
20
+
21
+ ## Operator sessions
22
+
23
+ Operator sessions are the signed-in operator's durable orchestrator
24
+ conversations: a hosted-only third store resource. A session
25
+ belongs to the operator who created it; other operators of the same repository
26
+ can read it and cannot write to it (`403 auth` on non-owner writes). Every
27
+ write is attributed to the token's signed user — never a client-supplied
28
+ identity — and carries no `via` marker: session events are the delegate's own
29
+ log. Writes of any kind to an archived session are `409 refusal`, and the
30
+ archived status is terminal.
31
+
32
+ | Method and path | Result |
33
+ |---|---|
34
+ | `GET …/sessions` | The repository's session records, newest update first. Readable by any operator of the repository. |
35
+ | `POST …/sessions` | `{"title"?:"…"}` → `201` + the created `SessionRecord`; the signed-in operator owns it. |
36
+ | `GET …/sessions/{sid}` | `{session, state, turns}` where `state` is the reducer's derived state (`status`, `openTurn`, `pendingApproval`, `wakeGlobs`, `wakeCursors`, `turns`) and `turns` the ordered turn list. Readable by any operator of the repository. |
37
+ | `POST …/sessions/{sid}/messages` | `{"text":"…"}` → appends `message.posted`. Owner only. |
38
+ | `PUT …/sessions/{sid}/wake` | `{"globs":["…"]}` (possibly empty) → appends `session.wake-set`. Owner only. |
39
+ | `POST …/sessions/{sid}/approvals` | `{"turn":"…","toolCallId":"…","decision":"approve"\|"deny"}` → `approval.answered`. Owner only; `409 refusal` when the reduced state has no matching pending approval. |
40
+ | `POST …/sessions/{sid}/archive` | Empty body → `session.archived`. Owner only; `409 refusal` when already archived. |
41
+ | `GET …/sessions/{sid}/turns/{turn}/stream?since=N&wait=N` | The turn's stream read: `{chunks,status,outcome?,artifact?}` with `since` strictly greater-than and the same bounded-wait semantics as the stream protocol (whole seconds, clamped at 30). Unknown turn is `404 not-found`. Readable by any operator of the repository. |
42
+
43
+ Session state is a reduction of the session's event log, never a stored
44
+ column; a `GET …/sessions/{sid}` response therefore always reflects the
45
+ session's full history. The API never exposes raw session-event append: the
46
+ turn runner (a later ticket) is the only producer of turn facts.
47
+
48
+ ## Reads
49
+
50
+ | Method and path | Result |
51
+ |---|---|
52
+ | `GET …/builds?scope=active\|queued\|all` | Build summaries, newest update first. `queued` means active plus queued, matching `ab builds --queued`. |
53
+ | `GET …/builds/{slug}` | `{detail, dashboardRow}`; `dashboardRow` remains a `CLEANING` row after `build.aborted` and becomes `null` only when the dashboard stops listing it (after cleanup's `build.completed`). |
54
+ | `GET …/dashboard` | `{generatedAt, model, settingsHeader}`. `model` is the dashboard's rows, steps, elapsed timing inputs, harvest row, queue/capacity and settings projection. |
55
+ | `GET …/status` | Repository intake, pause, and default-auto-merge projection. |
56
+ | `GET …/harvest/status` | Harvest gate, runs, steps, recovery, and attention projection. |
57
+ | `GET …/builds/{slug}/artifacts/{kind}?rev=N` | Raw bytes (`application/octet-stream`) plus content-disposition and `X-Autobuild-Artifact-*` metadata headers. Omit `rev` for latest. |
58
+ | `GET …/tickets?state=S&label=L` | `{states,tickets,diagnostics,criteria,triageState,readyState}`. The two lifecycle names come from effective repository configuration (including provider fallback). With no `state`, `criteria.state` is `triageState`; repeated `label` parameters narrow that state with AND filters. An explicit `state` selects that exact backend workflow state. |
59
+ | `GET …/tickets/{id}` | `{ticket,blockers,build}`. Blockers include native `exists`/`resolved` status; `build` prefers an active matching repository build, otherwise the most recently updated one. |
60
+
61
+ For artifact reads, an absent `rev` selects the latest revision. A supplied value
62
+ must match `[0-9]+` (one or more ASCII base-10 digits) and represent an integer
63
+ from `0` through `Number.MAX_SAFE_INTEGER` (`9007199254740991`). All other
64
+ supplied forms return `400 validation`.
65
+
66
+ Dashboard reads use the latest durable, run-correlated `effectiveConfig`
67
+ repository artifact. Missing, corrupt, or invalid configuration returns a typed
68
+ `409 effective-config-unavailable`; the service never guesses from a checkout.
69
+ Clients poll these reads — the operator HTTP API exposes no push or long-poll
70
+ event transport. Streaming is provided as a CLI read surface: `ab watch`
71
+ streams build and repository events by polling the same event logs client-side
72
+ (the store protocol's `GET /builds/{slug}/events` and `GET /repos/{repo}/events`
73
+ reads), not as a transport on this API. `triageState`, `readyState`,
74
+ and every entry in `states` are backend state names and must be sent back verbatim
75
+ when used with the move control.
76
+
77
+ ## Controls
78
+
79
+ JSON bodies are strict: unknown fields are rejected.
80
+
81
+ | Method and path | Body |
82
+ |---|---|
83
+ | `POST …/builds/{slug}/control` | `{"action":"pause"\|"cancel-pause"\|"resume"\|"abort"\|"discard"\|"auto-merge-on"\|"auto-merge-off"}` |
84
+ | `POST …/builds/{slug}/answer` | One answer variant described below. |
85
+ | `PUT …/settings/intake` | `{"enabled":boolean}` |
86
+ | `POST …/settings/intake/toggle` | Empty body. |
87
+ | `PUT …/settings/auto-merge-default` | `{"enabled":boolean}` |
88
+ | `POST …/settings/auto-merge-default/toggle` | Empty body. |
89
+ | `POST …/bulk-control` | `{"action":"pause"\|"resume"}`. The hold fact, intake fact, then eligible build events are written in that order. |
90
+ | `POST …/harvest/control` | `{"action":"toggle-gate"}` or `{"action":"run","run":"…"}`. A run action is bound to that concrete projected run. |
91
+ | `POST …/tickets` | `{"title":"…","body":"…","labels"?:[],"state"?:"…","blockedBy"?:[]}`; omitted state preserves the backend default. |
92
+ | `PATCH …/tickets/{id}` | Any nonempty subset of `title`, `body`, and complete-replacement `labels`. Body bytes are not normalized. |
93
+ | `POST …/tickets/{id}/move` | `{"state":"backend state name"}`. |
94
+ | `POST …/tickets/{id}/block` | `{"blockerIds":["…"]}`. |
95
+ | `POST …/tickets/{id}/unblock` | `{"blockerIds":["…"]}`. |
96
+
97
+ Answer variants:
98
+
99
+ ```json
100
+ {"resolution":"guidance","text":"…"}
101
+ {"resolution":"retry"}
102
+ {"resolution":"dismiss","text":"optional audit text"}
103
+ {"resolution":"review-round-ceiling","ceiling":4,"text":"optional guidance"}
104
+ {"resolution":"revise-spec","origin":"body","body":"replacement spec","text":"optional guidance"}
105
+ {"resolution":"revise-spec","origin":"ticket","body":"current amended ticket body","text":"optional guidance"}
106
+ ```
107
+
108
+ The retry object is deliberately bare: adding `text` is a `400 validation`
109
+ rather than silently changing the resolution to guidance. A revision object may
110
+ also carry `ceiling` only to receive the shared `incompatible-answer-options`
111
+ refusal; a ceiling and spec revision cannot be performed together.
112
+ The hosted service has no ticket-provider credentials. For ticket-origin
113
+ revision, a trusted caller fetches the current ticket body and supplies it; the
114
+ build must still have a recorded ticket. Revision conformance, lazy retry,
115
+ artifact metadata, event ordering, and refusal rules are the same as the CLI.
116
+
117
+ ## The registry's protocol face: `POST …/tools/{tool}`
118
+
119
+ One generic route executes any entry of the agent tool registry (the same
120
+ closed table `ab mcp` serves over stdio and the hosted `/mcp` endpoint serves
121
+ over Streamable HTTP): the body is the tool's validated input — `repo`
122
+ included and required to equal the URL's repository — and the response is the
123
+ registry result verbatim. The verified operator token supplies the acting
124
+ identity and, when minted with one, the `via` attribution marker; the body
125
+ never does. Failures keep the shared `{kind,error,code?,progress?}` shape:
126
+ validation is `400`, auth `403`, not-found `404`, conflict and refusal `409`,
127
+ internal `500`. The route adds no authority of its own — it is the registry
128
+ behind the token check — so a tool available here is exactly the tool table,
129
+ and the table's contract suite is the single gate.
130
+
131
+ ### Success results
132
+
133
+ Build control returns one of:
134
+
135
+ - `{kind:"command",slug,command,event}` after writing a pause, resume, abort,
136
+ discard, or per-build auto-merge command. `command` is the durable command;
137
+ successful cancel-pause therefore returns `command:"resume"`.
138
+ - `{kind:"answer-required",slug,escalationIds}` when `action:"resume"` targets
139
+ a blocked build. This is a successful prompt transition but **does not append
140
+ an event**; submit one of the answer requests next.
141
+ - `{kind:"answered",slug,count,resolution,resumed,...}` from the answer route.
142
+ `resolution` is `guidance`, `retry`, `dismiss-finding`, or `revise-spec`.
143
+ Depending on the operation, the result also includes `remainingOpen`,
144
+ `reviewRoundCeiling:{loop,value}`, `specRev`, `authorizedEarlier`, or a
145
+ `terminalSignal` describing a terminal status, pending abort, or ended PR.
146
+
147
+ Repository setting writes and toggles return `{enabled,event}`. Harvest gate
148
+ toggle returns `{command:"pause"|"resume",event}`; a concrete-run action
149
+ returns `{action:"resume"|"acknowledge",event}`. Bulk control returns
150
+ `{direction,slugs,paused,intake}`, where `slugs` is the write-ordered set of
151
+ builds that received a command. Every `event` is the complete durable envelope
152
+ including repository/build id, sequence, timestamp, actor, type, and payload.
153
+
154
+ ## Errors
155
+
156
+ JSON errors have `{kind,error,code?,progress?}`. Malformed input is `400
157
+ validation`; missing resources/artifacts are `404 not-found`; missing/invalid
158
+ credentials are `401 auth`; a valid non-operator scope is `403 auth`; version
159
+ skew and unavailable projections are `409 conflict`. A build outside the URL's
160
+ repository is deliberately hidden as `404 not-found` with `unknown build`,
161
+ consistently for detail, control, answer, and artifact routes. Control refusals are `409
162
+ refusal` and preserve the shared `BuildControlError` code and exact reason text.
163
+ A partial bulk failure uses code `bulk-partial` and includes the durable write
164
+ progress and unattempted builds. Unexpected failures are `500 internal`.
165
+
166
+ ## Browser gateway
167
+
168
+ The same deployment serves the web dashboard through `/api/web/repos/{repo}/…`.
169
+ That route is not a second public bearer-token API: it requires a current
170
+ Better Auth HTTP-only cookie, rechecks the deployment email and repository
171
+ allowlists, rejects cross-origin JSON controls, and delegates only the dashboard,
172
+ build, settings, and harvest operator suffixes listed above. It replaces caller-supplied authorization/version
173
+ headers with a server-minted token that expires after 30 seconds and carries
174
+ the normalized signed-in email. Consequently every durable control event has
175
+ the browser user's human actor while no token or signing secret reaches client
176
+ code. Responses are private/no-store; a 401 sends the application back to sign
177
+ in. Browser clients poll the visible dashboard every two seconds; the browser
178
+ surface offers no streaming of its own — live transcript streaming remains
179
+ absent here, and the streaming read surface is the CLI's `ab watch`, which
180
+ polls the store's event reads client-side. Delegated bearer tokens remain
181
+ server-side.
182
+
183
+ The API does not expose phase-session commands, runner startup, a push or
184
+ long-poll streaming transport, or a generic event-append operation; event
185
+ streaming is composed client-side by `ab watch`, which polls the store's
186
+ event reads.