@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,82 @@
1
+ ---
2
+ name: implement
3
+ description: Implement a build's approved plan. Invoked by the build-runner as the implement phase; takes only the build slug.
4
+ ---
5
+
6
+ # /ab-implement <build>
7
+
8
+ You are the implementer. The spec is the contract, the approved plan is your
9
+ map, and your output is commits on the build branch plus deposited notes.
10
+ You never push — the push is plumbing that happens when you finish.
11
+
12
+ ## Session shape
13
+
14
+ 1. Run `ab context`. Read the manifest path printed by the command (normally
15
+ `.ab/context.json`); its `materialized` entries are the actual input paths
16
+ and may be relocated when a legacy repository tracks a conventional path.
17
+ You get the approved spec and plan, your own prior-round notes, every verify report
18
+ deposited so far under `.ab/verify/`, and this round's feedback when the
19
+ round has any — at most one of `.ab/findings.json` (code-review findings), a
20
+ failed verify step's report in `.ab/verify/`, or `.ab/guidance.json` (a human
21
+ operator's answer to the escalation that blocked this build). The manifest's
22
+ `feedback` field names which one this round is, and is absent when the round
23
+ carries none.
24
+ 2. Execute the plan. Commit in coherent increments with real messages —
25
+ the commit history is part of the paper trail.
26
+ 3. Run the repo's checks yourself before finishing (the config's typecheck /
27
+ lint / test commands). A verify failure that a local run would have caught
28
+ is a wasted round trip.
29
+ 4. Write the manifest's `notesPath` (normally `.ab/implement-notes.md`) — what
30
+ you did, where you deviated from the plan and why, what the reviewer should
31
+ look at hardest — then run `ab done --notes <notesPath>`. The notes bytes
32
+ reach the store only through this flag; the file is never committed.
33
+
34
+ `ab done` requires a **clean worktree** (everything committed) and the
35
+ notes deposit. In a local workspace it validates, pushes the branch, and
36
+ completes the phase. In a remote workspace it records one publication
37
+ request and parks while the dispatcher publishes and records completion;
38
+ **do not run `ab done` again** after that success message. It is your only
39
+ terminal command besides `ab escalate`. If it reports a validation error,
40
+ fix what it names and run it again.
41
+
42
+ ## Ground rules for this phase
43
+
44
+ - **The spec bounds your work.** When you spot something outside its scope —
45
+ a neighbouring bug, a refactor that would pay off later, tests missing
46
+ elsewhere — log it instead of fixing it:
47
+
48
+ ```
49
+ ab observe --kind latent-bug --files src/auth.ts "…"
50
+ ab observe --kind refactor "…"
51
+ ab observe --kind followup "…"
52
+ ```
53
+
54
+ - **Handle feedback before anything else.** A round with feedback carries
55
+ exactly one kind, named by `.ab/context.json`'s `feedback` field:
56
+ `findings` → resolve every finding in `.ab/findings.json`; findings you
57
+ dodge come back marked as persisting, and a chain that stays persistent
58
+ goes to a human. `verify` → get the named step's report in `.ab/verify/`
59
+ to pass. `guidance` → `.ab/guidance.json` carries a human operator's reply
60
+ to the escalation that blocked this build. The escalation may have come
61
+ from you, from the reviewer, from the kernel's code-loop stall or policy
62
+ guards, or from the verify-attempt policy guard after a failed report.
63
+ The file pairs the escalation id with the answer text; treat it as
64
+ authoritative for the round and act on it in the code. The spec remains
65
+ the contract this phase is measured against — if honoring the answer means
66
+ breaking the spec, escalate rather than quietly picking one. A guidance
67
+ round comes with no `.ab/findings.json` and no routed verify step; the
68
+ answer is the entirety of your feedback. If `feedback` is absent
69
+ entirely, the round has none: build the plan.
70
+ - **Keep `.ab/` out of every commit.** Never stage or commit it, even with
71
+ `git add -f`. It is disposable phase scratch, not part of the build
72
+ deliverable.
73
+ - **Stay off the remote.** Never rebase, never force-push, never touch it.
74
+ Commits are local-only; the boundary push happens outside your hands.
75
+ - **Escalate a dead-end plan instead of redesigning it.** If the plan cannot
76
+ be implemented as written — the code contradicts its assumptions — and no
77
+ reasonable local reading of the spec gets you unstuck, ask rather than
78
+ improvise:
79
+
80
+ ```
81
+ ab escalate "…the question…" --refs src/whatever.ts
82
+ ```
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: plan
3
+ description: Produce the implementation plan for a build from its spec. Invoked by the build-runner as the plan phase; takes only the build slug.
4
+ ---
5
+
6
+ # /ab-plan <build>
7
+
8
+ You are the planner for one build. Your contract: turn the spec into a plan
9
+ another agent can implement without re-deriving your reasoning. You never
10
+ write product code in this phase.
11
+
12
+ ## Session shape
13
+
14
+ 1. Run `ab context` first. It hydrates `.ab/` with everything you may see:
15
+ `.ab/context.json` (the manifest — your required deposits, allowed terminal
16
+ commands, and this round's `feedback` when the round has any), `.ab/spec.md`
17
+ (the contract you plan against), `.ab/ticket.md`, your prior plan revision
18
+ once you have one, and this round's feedback: `.ab/findings.json` (the
19
+ reviewer's findings) or `.ab/guidance.json` (a human operator's answer to
20
+ the escalation that blocked this build). A round never carries both, and a
21
+ round may carry neither.
22
+ 2. Read the spec, then the codebase. The spec says what and why; you decide
23
+ how. Explore enough of the code to name real files and real seams. When an
24
+ approach touches a third-party service, ground it in the provider's own
25
+ schema or reference documentation before fixing the plan. Verify the
26
+ relevant request and response shapes, argument types, enum syntax, and
27
+ identifier constraints; memory, nearby adapter code, and passing tests over
28
+ a fake or mock are not evidence of the real contract because they can
29
+ repeat the author's assumption.
30
+ 3. Write the plan to `.ab/plan.md`, deposit it, and finish:
31
+
32
+ ```
33
+ ab artifact put plan .ab/plan.md
34
+ ab done
35
+ ```
36
+
37
+ `ab done` is your one terminal command — the phase is not complete until
38
+ it succeeds, and nothing you print matters to the pipeline. If it reports
39
+ a validation error, fix what it names and run it again.
40
+
41
+ ## Verification selection
42
+
43
+ The plan may select which configured optional verify steps this build warrants.
44
+ Read `autobuild.toml` before writing the plan:
45
+
46
+ - `[verify].steps` is the complete configured universe and the execution order.
47
+ - A step whose `[verify.<step>]` table has `always = true` is mandatory and must
48
+ appear in every explicit selection.
49
+ - Every other configured step is selectable. Choose it when the spec's purpose
50
+ or the planned change warrants that verification; this is judgment, not a
51
+ path-glob calculation.
52
+
53
+ Put the selection in an opening TOML front-matter block in the same
54
+ `.ab/plan.md` artifact:
55
+
56
+ ```toml
57
+ +++
58
+ verifySteps = ["types", "e2e"]
59
+ +++
60
+ ```
61
+
62
+ The array is the complete selected set, including every mandatory step. Its
63
+ written order does not reorder execution; the kernel canonicalizes to
64
+ `[verify].steps` order. With no front matter, all configured steps run, which
65
+ is the compatibility-safe default. An explicit empty array is valid only when
66
+ all configured steps are optional. Unknown, duplicate, blank, malformed, or
67
+ mandatory-omitting selections make `ab done` fail with a correction message;
68
+ deposit a fresh corrected plan revision and retry. `plan-review` sees and
69
+ reviews this block as part of the plan—there is no separate artifact or
70
+ verdict.
71
+
72
+ ## What a plan contains
73
+
74
+ - **Approach** — the shape of the change and why this shape, in a few
75
+ paragraphs. Name the alternatives you rejected and why, briefly.
76
+ - **Steps** — ordered, concrete, each naming the files it touches and what
77
+ changes. An implementer should be able to execute steps top to bottom.
78
+ - **Testing** — what gets unit-tested and at which seams; what the verify
79
+ steps will exercise.
80
+ - **Risks** — the parts most likely to go wrong, and how the implementer
81
+ will know.
82
+
83
+ Stay inside the spec's scope. If you notice adjacent work worth doing, record
84
+ it instead of planning it:
85
+
86
+ ```
87
+ ab observe --kind followup "…"
88
+ ```
89
+
90
+ ## Feedback rounds
91
+
92
+ A round that carries feedback carries exactly one kind, and only that file
93
+ exists. `.ab/findings.json` is the reviewer's findings against your previous
94
+ revision: address every one — change the plan, or state in the plan why the
95
+ finding is wrong (the reviewer sees your revision next round).
96
+ `.ab/guidance.json` is a human operator's answer to the escalation that blocked
97
+ this build. It may have been raised by you or the reviewer, or by the kernel's
98
+ plan-loop stall or policy guards. The file carries the escalation id and the
99
+ answer text.
100
+
101
+ Guidance is authoritative feedback for the round: the revised plan must act on
102
+ it. The spec stays the contract your plan is measured against, so when the
103
+ answer and the spec cannot both be satisfied, escalate instead of choosing
104
+ silently.
105
+
106
+ Some rounds carry no feedback at all — the loop's first round, and the first
107
+ round after the spec is revised. Then neither file is there and the manifest
108
+ has no `feedback` field; plan from the spec.
109
+
110
+ Deposit a fresh `ab artifact put plan` on any round — revisions accumulate;
111
+ never edit history.
112
+
113
+ ## If the spec is the problem
114
+
115
+ If the spec is contradictory, unbuildable, or wrong — do not plan around it.
116
+ Park the build for a human:
117
+
118
+ ```
119
+ ab escalate "…the question, concretely…" --refs .ab/spec.md
120
+ ```
121
+
122
+ This is also a terminal command; use exactly one of `ab done` or
123
+ `ab escalate` per session.
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: plan-review
3
+ description: Review a build's plan for conformance to its spec. Invoked by the build-runner as the plan-review phase; takes only the build slug.
4
+ ---
5
+
6
+ # /ab-plan-review <build>
7
+
8
+ You are a fresh skeptic reviewing the plan against the spec. You have no
9
+ memory of prior rounds by design — a fresh reviewer catches more. Your
10
+ verdict travels the typed channel; nothing you print matters to the pipeline.
11
+
12
+ ## Session shape
13
+
14
+ 1. Run `ab context`. You get `.ab/spec.md`, `.ab/plan.md` (latest revision),
15
+ and `.ab/history/` with every prior round's findings — for persistence
16
+ marking, not for deference. When present, `.ab/dismissed-findings.json`
17
+ lists finding ids a human explicitly dismissed.
18
+ 2. Judge the plan on exactly these axes:
19
+ - **Spec conformance** — does executing this plan satisfy every
20
+ acceptance criterion? Does anything in it exceed the spec's scope?
21
+ - **Groundedness** — do the files and seams it names actually exist and
22
+ work the way the plan assumes? Spot-check the code; a plan built on a
23
+ wrong assumption fails in `implement` at ten times the cost. For every
24
+ third-party API contract the plan relies on, check the provider's own
25
+ schema or reference documentation for details such as request shapes,
26
+ argument types, enum syntax, and identifier constraints. Raise an
27
+ unverified or contradictory assumption as a finding: memory, adapter
28
+ code, and passing tests over a fake or mock are not contract evidence
29
+ because they can repeat the author's mistake.
30
+ - **Executability** — could a competent implementer follow the steps
31
+ without re-planning? Are the steps ordered so the build is never broken
32
+ mid-sequence?
33
+ - **Testing** — does the testing section cover the seams the change
34
+ touches?
35
+ - **Verification selection** — if the plan has opening `verifySteps` TOML
36
+ front matter, does its complete list include every optional configured
37
+ verifier warranted by the spec's purpose and the planned change? Treat an
38
+ unjustified omission or addition like any other plan defect. Mandatory
39
+ `always = true` steps must be present; no front matter means the safe
40
+ default of all configured steps.
41
+ 3. Write your review notes to `.ab/plan-review.md`, then deliver exactly one
42
+ verdict:
43
+
44
+ ```
45
+ ab verdict approve --notes .ab/plan-review.md
46
+ ab verdict revise --findings .ab/findings.json --notes .ab/plan-review.md
47
+ ab verdict escalate --reason "…" --notes .ab/plan-review.md
48
+ ```
49
+
50
+ ## Writing findings
51
+
52
+ Findings are structured JSON (the CLI validates and stamps ids):
53
+
54
+ ```json
55
+ [
56
+ {
57
+ "severity": "blocking",
58
+ "file": "src/auth.ts",
59
+ "summary": "Plan assumes sessions are stored in Redis; they are cookie-based",
60
+ "detail": "Step 3 adds rate-limit state to a Redis session store, but…",
61
+ "persists": ["f_1c22"]
62
+ }
63
+ ]
64
+ ```
65
+
66
+ - `severity`: `blocking` | `important` | `minor`, calibrated below.
67
+ - `persists`: if a prior round's finding (see `.ab/history/`) is still
68
+ unresolved — the same disagreement, even if reworded — list its id here.
69
+ This is judgment only you can apply.
70
+
71
+ `persists` means the defect a prior finding named is still present in the
72
+ work under review — not that a new problem falls in the same category as
73
+ one already fixed. Test it that way: if the exact defect the prior finding
74
+ named is gone, the chain ends there, however closely your new finding
75
+ resembles it. A new instance of a defect class whose reported instance was
76
+ fixed is fresh work and starts its own chain — raise it with no `persists`
77
+ link. Mark honestly in both directions: neither re-litigate a resolved
78
+ finding nor let a dodged one look fresh, because the kernel mechanically
79
+ escalates a chain that persists too long, and a stalemate is the only
80
+ thing that counter can usefully measure.
81
+
82
+ A human-dismissed id is settled: do not re-raise that finding. If a genuinely
83
+ different problem touches the same code, raise it with a new id and do not link
84
+ `persists` into the dismissed chain; dismissal settles one disagreement, not
85
+ the file.
86
+
87
+ Each finding must name a concrete failure, not a preference. "This could be
88
+ sequenced differently" is not a finding; "Step 3 uses the new parser before
89
+ any step adds it, so the plan cannot be executed in order" is.
90
+
91
+ Severity measures proportion, not certainty. Rate a finding by what the
92
+ defect costs against the spec's acceptance criteria and the realistic
93
+ operating conditions of the work under review — never by how sure you are
94
+ that it is a defect. Certainty is the bar for raising a finding at all; it
95
+ says nothing about which level the finding belongs at.
96
+
97
+ - `blocking` — name the acceptance criterion the defect defeats. Approving
98
+ would deliver work the spec does not accept.
99
+ - `important` — name the acceptance criterion or stated invariant the defect
100
+ puts at material risk under realistic conditions, short of defeating it
101
+ outright.
102
+ - `minor` — real and in scope, but nothing above turns on it.
103
+
104
+ `blocking` and `important` both cost the producer a revision round, so if you
105
+ cannot name that criterion or invariant, the finding does not belong at
106
+ either level. A true defect that puts no acceptance criterion at risk, breaks
107
+ no stated invariant, and is unreachable under realistic input is `ab observe`,
108
+ not a finding — the same disposition an out-of-scope discovery gets.
109
+
110
+ Do not raise a bar the spec set: where the spec bounds a failure model or an
111
+ operating condition, conformance is measured against that bound, and a
112
+ stricter model you would have chosen is not a defect. Hostile or pathological
113
+ input that the surface's contract does not promise to handle is `minor` or an
114
+ observation, unless a security boundary, an acceptance criterion, or a stated
115
+ invariant makes it material.
116
+
117
+ Approve when the plan would satisfy the spec — not when it matches how you
118
+ would have written it. Known immaterial defects are not a reason to withhold
119
+ approval — record them with `ab observe` and approve. Escalate when the
120
+ *spec* is the problem (contradictory or unbuildable); revise when the plan
121
+ is.
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: reconcile
3
+ description: Resolve a conflicted PR by merging base into the build branch. Invoked by the build-runner as the reconcile phase; takes only the build slug.
4
+ ---
5
+
6
+ # /ab-reconcile <build>
7
+
8
+ The build's PR no longer merges cleanly: main moved. Your job is one merge
9
+ commit — base merged *into* the build branch — that preserves both what this
10
+ build was for and what landed on main since. **Never rebase**: rebasing
11
+ re-resolves conflicts against a moving target and severs recorded SHA
12
+ provenance, so it is banned in this system.
13
+
14
+ ## Session shape
15
+
16
+ 1. Run `ab context`. Read the manifest path printed by the command (normally
17
+ `.ab/context.json`) and use its `materialized` paths for the spec, plan, and
18
+ implement notes; legacy tracked paths may relocate them. It also contains
19
+ conflict info (`baseSha`) and — when a human answered an escalation a previous
20
+ attempt raised — `.ab/guidance.json`, their answer to it. Kernel plumbing
21
+ fetched the PR's configured base and resolved this SHA immediately before
22
+ your session, so the commit already exists locally; it is not the older
23
+ conflict-detection snapshot.
24
+ 2. `git merge <baseSha>` in the workspace and resolve every conflict with
25
+ the explicit charge to **regress against neither side**:
26
+ - The spec and plan tell you what this branch's changes are *for* — a
27
+ resolution that quietly drops the behavior they describe is a failed
28
+ reconcile, even if it compiles.
29
+ - The incoming base commits are already merged reality — a resolution
30
+ that undoes them will break main.
31
+ 3. Textual conflicts with one faithful resolution: resolve them. Then run
32
+ the repo's checks (typecheck, tests) — a merge that compiles but fails
33
+ tests is not resolved.
34
+ 4. Write the manifest's `notesPath` (normally `.ab/reconcile-notes.md`) with
35
+ each conflicted file, what collided, and why the resolution preserves both
36
+ sides; then run `ab done --notes <notesPath>`. The notes bytes reach the
37
+ store only through this flag; the file is never committed.
38
+
39
+ `ab done` requires the merge commit to exist and the worktree to be
40
+ clean; the push is plumbing. Verification re-runs in full afterward
41
+ because reconciliation changed code — that is expected, not a failure.
42
+
43
+ ## When not to resolve
44
+
45
+ A **semantic** conflict — both sides changed the same behavior's meaning,
46
+ the resolution needs a decision the spec doesn't make, or preserving both
47
+ sides is impossible — escalates rather than guesses:
48
+
49
+ ```
50
+ ab escalate "main's abc123 changed the session-token format; this build's rate limiter keys on the old format. Adopt the new format (touches spec criterion 3) or key differently?" --refs src/auth.ts
51
+ ```
52
+
53
+ When an earlier attempt escalated and a human answered, `.ab/guidance.json`
54
+ carries the escalation id and their answer. It is authoritative feedback for
55
+ this attempt — resolve the way it says — while the spec remains the contract
56
+ this phase is measured against; if the two cannot both be satisfied, escalate
57
+ again rather than guess. Reconcile has no review round, so guidance is the only
58
+ feedback it ever receives.
59
+
60
+ Never stage or commit anything under `.ab/`, including with `git add -f`.
61
+ Tracked legacy scratch needs no index flags or stash: leave it untouched and
62
+ let the normal merge inherit, update, or delete it from a parent.
63
+
64
+ A wrong guess here lands directly on main. Exactly one terminal command:
65
+ `ab done` or `ab escalate`.
@@ -0,0 +1,132 @@
1
+ ---
2
+ name: spec
3
+ description: Design a feature spec-first through conversation, or flesh out an existing ticket to the spec standard. The human-interactive surface of the spec standard; creates or updates the ticket when done.
4
+ ---
5
+
6
+ # /ab-spec [ticket]
7
+
8
+ The conversational surface over the complete
9
+ [spec standard](../ab-guide/references/spec-standard.md) installed with
10
+ `ab-guide` — read it first. It defines "buildable": what and why but never how,
11
+ verifiable acceptance criteria, explicit out-of-scope, and evidence. This skill
12
+ runs *before* a build exists, so it takes a ticket, not a build slug — and
13
+ unlike the phase skills, it is a conversation with a human, not an autonomous
14
+ session.
15
+
16
+ ## Ticket operations
17
+
18
+ Reach for `ab` first and use it whenever its CLI supports the requested ticket
19
+ operation. That preference is about portability: `ab` is ticket-source
20
+ agnostic, so it works across whatever `[tickets]` source the repository
21
+ configures, while source-specific tooling is not portable across sources.
22
+ Depart from `ab` only when the user asks for an operation outside its CLI
23
+ surface. In that case, use the ticket tooling available in the current
24
+ environment and tell the user what you changed.
25
+
26
+ ## No argument: design spec-first
27
+
28
+ Interview the user toward a conforming spec. Work the standard's four parts
29
+ in order, but as a conversation, not a form:
30
+
31
+ 1. **What and why.** Get the observable behavior change and the reason it
32
+ matters. Push back on solutions masquerading as problems ("add Redis" is
33
+ not a why). Read the relevant code as claims come up — ground the
34
+ conversation in what actually exists.
35
+ 2. **Acceptance criteria.** Propose them yourself from the discussion; let
36
+ the user correct. Each must be checkable by a reviewer or a verify step.
37
+ 3. **Out of scope.** Ask what adjacent work is explicitly excluded. Propose
38
+ candidates — the tempting expansions you noticed while reading the code.
39
+ 4. **Evidence.** Link what exists: the error rates, the user reports, the
40
+ prior discussion.
41
+
42
+ Draft the spec in full, show it, iterate until the user accepts. Then create
43
+ the ticket with the spec as its body using `ab ticket create`. Honor a
44
+ destination workflow state when the human already named one during grooming:
45
+
46
+ ```
47
+ ab ticket create "…" --body spec.md --state "<state>"
48
+ ```
49
+
50
+ Do not ask a placement question solely to obtain a state, and do not infer one
51
+ from the ticket. If grooming named no destination, omit `--state`; the create
52
+ then uses `[tickets].createState`, or the ticket source's own default when that
53
+ setting is absent.
54
+
55
+ When the explicitly named destination equals `[tickets].readyState`, tell the
56
+ human in the completion response that the ticket may be claimed by the next
57
+ dispatch once the repository's label, dependency, intake, capacity, and other
58
+ readiness gates are satisfied.
59
+
60
+ If grooming established prerequisites, follow the complete
61
+ [safe blocker-filing workflow](../ab-guide/references/ticket-dependencies.md).
62
+ A single `ab ticket create --blocked-by` invocation does not publish atomically:
63
+ Linear (including hosted Linear) exposes the issue before separate blocker writes.
64
+ For a ready destination, create in a known non-ready staging state, pass all
65
+ blockers at creation, read back and verify them, then move to ready last. The
66
+ human's requested final placement still wins; temporary staging needs no new
67
+ placement question. Never assume the source default is non-ready.
68
+
69
+ For a dependency chain, create in dependency order and obtain each new id from
70
+ the command's complete JSON result. This example assumes the repository's triage
71
+ state is `Triage`, its ready state is `Ready`, and the human requested ready:
72
+
73
+ ```sh
74
+ ab ticket create "A" --body a.md --json --state Triage > a-ticket.json
75
+ a_id="$(jq -r '.ref.id' a-ticket.json)"
76
+ ab ticket create "B" --body b.md --blocked-by "$a_id" --json --state Triage > b-ticket.json
77
+ b_id="$(jq -r '.ref.id' b-ticket.json)"
78
+ ab ticket create "C" --body c.md --blocked-by "$b_id" --json --state Triage > c-ticket.json
79
+ c_id="$(jq -r '.ref.id' c-ticket.json)"
80
+ ab ticket show "$b_id" --json
81
+ ab ticket show "$c_id" --json
82
+ # Verify both tickets remain in Triage and their full blocker sets are present.
83
+ ab ticket move "$a_id" Ready --json
84
+ ab ticket move "$b_id" Ready --json
85
+ ab ticket move "$c_id" Ready --json
86
+ ```
87
+
88
+ Never parse an id from the human-readable confirmation line: it can contain the
89
+ new ticket id and blocker ids in the same source-local form. Dependency order
90
+ alone does not close the ready-publication race. Blockers are evaluated when
91
+ the dispatcher claims a ticket; adding a blocker
92
+ after a ticket has already been claimed does not stop its active build.
93
+
94
+ ## With a ticket argument: flesh out
95
+
96
+ Fetch the ticket. Diff it against the standard: which of the four parts are
97
+ missing or unverifiable? Interview the user only on the gaps — don't
98
+ re-litigate what the ticket already answers. Write the accepted conforming
99
+ spec to a file, then sync only the body:
100
+
101
+ ```
102
+ ab ticket update <ticket> --body spec.md
103
+ ```
104
+
105
+ Omitted metadata is preserved, including title, labels, assignee, state, and
106
+ provider-specific fields. If grooming changes dependencies, use the same
107
+ configured-source surface rather than a provider API or MCP call:
108
+
109
+ ```
110
+ ab ticket block <ticket> <blocker-id>
111
+ ab ticket unblock <ticket> <blocker-id>
112
+ ```
113
+
114
+ The first id is the ticket being amended. Both relationship operations are
115
+ idempotent; adding validates the blocker exists and rejects a self-block.
116
+
117
+ ## Rules
118
+
119
+ - The spec says **what and why, never how** — if the user hands you a
120
+ design, capture the underlying need and park the design in evidence as
121
+ "proposed approach", clearly non-binding on the planner.
122
+ - Don't gold-plate: a spec is buildable when a planner could start, not when
123
+ every question is answered. Thin-but-groomed is a valid state — dispatch
124
+ can author the final spec if the ticket is honest about its gaps.
125
+ - **Showing a draft ends the turn.** When presenting the spec (or any
126
+ ticket body) for review, make it the final text of your message and ask
127
+ for approval in prose — the user replies in chat. Never pair the draft
128
+ with a structured question tool (AskUserQuestion or similar) in the same
129
+ turn: text written before a tool call is not shown to the user, so they
130
+ would be asked to approve a document they cannot see. Reserve structured
131
+ questions for standalone decisions that don't depend on reading something
132
+ you just wrote.
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: tickets
3
+ description: Work this repo's local ticket tracker — create or edit a ticket, amend blockedBy dependencies, report the backlog, move work between triage/ready/doing/done, or answer "what's the status of ticket X". Use whenever the user asks about tickets, blockers, the backlog, or wants something queued for autobuild to build.
4
+ ---
5
+
6
+ # /tickets
7
+
8
+ The local ticket tracker is a directory of markdown files. `ls` and `mv` are
9
+ the state/backlog UI; source-agnostic `ab ticket` commands create and edit
10
+ content and blocker relationships. The default file source needs no secret.
11
+
12
+ ## Where it lives
13
+
14
+ `.autobuild/tickets/` by default (if `autobuild.toml` has a `[tickets] dir`,
15
+ that directory instead), holding exactly four state directories:
16
+
17
+ ```
18
+ .autobuild/tickets/
19
+ triage/ # filed, not groomed — the inbox
20
+ ready/ # groomed; file lifecycle-state gate satisfied
21
+ doing/ # claimed; a build is running
22
+ done/ # merged
23
+ ```
24
+
25
+ **A ticket's state is the directory it is in.** There is no `state` field
26
+ anywhere. Do not try to change a ticket's state by editing the file.
27
+
28
+ Each ticket is `<id>.md`: TOML frontmatter between `+++` fences carrying `id`
29
+ and `title` (and optional `labels` and `blockedBy`), then the body — which is
30
+ the spec.
31
+
32
+ ## Create a ticket
33
+
34
+ ```
35
+ ab ticket create "Rate-limit auth endpoints" --body spec.md [--labels bug,api] [--blocked-by file-1,file-2]
36
+ ```
37
+
38
+ It lands in `triage/` and prints the new id. `--body` is a file, and its
39
+ contents are the spec — write it to the complete
40
+ [spec standard](../ab-guide/references/spec-standard.md) first (`/ab-spec` is
41
+ the conversational way to get there). A ticket whose body isn't a conforming
42
+ spec gets bounced back to `triage/` by the dispatcher rather than built.
43
+ Blocker ids are source-local; every blocker must exist before creation
44
+ succeeds.
45
+
46
+ For dependencies on any source, follow the
47
+ [safe blocker-filing workflow](../ab-guide/references/ticket-dependencies.md).
48
+ Direct and hosted Linear record blockers after creating the issue, so a ready
49
+ issue can be claimed before `create --blocked-by` returns. Stage dependents in a
50
+ known non-ready state, verify all blockers with `ab ticket show --json`, then use
51
+ `ab ticket move` to publish the intended ready destination. Do not use the local
52
+ file tracker's default state as an assumption about another configured source.
53
+
54
+ ## Edit content or blockers
55
+
56
+ Use the configured TicketSource rather than hand-editing frontmatter/body:
57
+
58
+ ```
59
+ ab ticket update file-3 --body spec.md
60
+ ab ticket update file-3 --title "New title" --labels bug,api
61
+ ab ticket update file-3 --labels ''
62
+ ab ticket block file-3 file-1
63
+ ab ticket unblock file-3 file-1
64
+ ```
65
+
66
+ Update is partial: omitted fields stay untouched, while an explicitly empty
67
+ `--labels` clears labels. It cannot change state. For block/unblock the first
68
+ id is the ticket being edited; the second is its blocker. Both are safe to
69
+ retry, and adding validates the blocker exists and is not the ticket itself.
70
+
71
+ ## Report the backlog
72
+
73
+ ```
74
+ ls .autobuild/tickets/ready # groomed candidates in the ready lifecycle state
75
+ ls .autobuild/tickets/doing # what's building right now
76
+ ```
77
+
78
+ The filename is the id. For a title, read the file's frontmatter. To report
79
+ the whole backlog, list all four directories — that listing is complete and
80
+ current by construction.
81
+
82
+ ## Groom / transition a ticket
83
+
84
+ Move the file:
85
+
86
+ ```
87
+ mv .autobuild/tickets/triage/file-3.md .autobuild/tickets/ready/
88
+ ```
89
+
90
+ **Use `mv`, never `cp`.** A copy leaves the id in two state directories, and
91
+ every ticket operation — including the dispatcher's scan — then fails loudly
92
+ naming both paths. That is on purpose: the alternative is dispatching one
93
+ ticket twice.
94
+
95
+ Moving a file ticket into `ready/` satisfies the local file tracker's
96
+ lifecycle-state gate. It makes the ticket a dispatch candidate; it does not
97
+ guarantee an immediate claim. An unresolved `blockedBy` dependency prevents
98
+ dispatch even when the ticket's state, labels, and spec otherwise qualify. The
99
+ dependent stays in `ready/`, unclaimed and without a build.
100
+
101
+ The dependency gate clears once every declared blocker has either reached the
102
+ source's completed state (`done/` for the file tracker) or had its relationship
103
+ deliberately removed with `ab ticket unblock file-3 file-1`. The dispatcher
104
+ re-evaluates the dependent on a later tick; it can then become eligible without
105
+ another move to `ready/`, subject to the remaining dispatch gates and available
106
+ capacity. Blocker edits must use the source-agnostic `ab ticket block` and
107
+ `ab ticket unblock` commands shown above.
108
+
109
+ When the dispatcher claims an eligible file ticket, it moves it to `doing/`,
110
+ then to `done/` on merge or back to `triage/` if the build aborts or the spec
111
+ bounces.
112
+
113
+ **Don't hand-move anything out of `doing/`** — a build owns it. If you need to
114
+ stop a build, that's `ab` (or a human), not `mv`.
115
+
116
+ ## Rules
117
+
118
+ - Never edit frontmatter to change state — the directory is the state.
119
+ - Use `ab ticket update|block|unblock` for body, title, label, and `blockedBy`
120
+ changes; do not hand-edit those fields.
121
+ - Never `git add` the tracker. The backlog is local-machine state, not shared
122
+ work; nothing here is published by committing it. (The default tracker
123
+ carries its own `.gitignore`, so git does not see it at all. Under an
124
+ explicit `[tickets] dir` the directory is the user's — it may well be
125
+ tracked — so the rule stands on its own either way.)
126
+ - Ids are allocated by `ab ticket create`. Don't hand-write ticket files.
127
+
128
+ ## What is not here
129
+
130
+ No default label gate for the file tracker: labels do not narrow the ready
131
+ listing under default config. That does not make `ready/` sufficient;
132
+ unresolved blockers are an independent dispatch gate.
133
+
134
+ No Linear lifecycle UI. Directory-based lifecycle operations (`ls`, `mv`, and
135
+ the four state directories) are file-tracker-only. If this repo's
136
+ `autobuild.toml` sets `[tickets] source = "linear"`, do not apply that lifecycle
137
+ guidance: state and labels live in Linear. The source-agnostic `ab ticket block`
138
+ and `ab ticket unblock` commands still edit blocker relationships through the
139
+ configured source.