ultra-builder-pro-cli 0.20.0 → 0.22.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 (109) hide show
  1. package/.ultra-template/docs/research/README.md +26 -5
  2. package/.ultra-template/specs/discovery.md +1 -1
  3. package/.ultra-template/tasks/tasks.json +10 -3
  4. package/.ultra-template/templates/task-context.md +19 -0
  5. package/CHANGELOG.md +106 -0
  6. package/README.md +215 -41
  7. package/adapters/_shared/codex-assets.cjs +69 -11
  8. package/adapters/_shared/interaction-contract.cjs +36 -3
  9. package/adapters/_shared/runtime-assets.cjs +41 -1
  10. package/adapters/claude.js +7 -5
  11. package/adapters/codex.js +1 -1
  12. package/adapters/kimi.js +2 -8
  13. package/adapters/opencode.js +43 -30
  14. package/bin/orchestrator.js +64 -24
  15. package/docs/AGENT-CONTEXT.md +89 -49
  16. package/docs/ARCHITECTURE.md +112 -45
  17. package/docs/ARTIFACT-AUTHORITY.md +274 -0
  18. package/docs/COMMIT-HASH-BACKFILL.md +33 -90
  19. package/docs/DECISIONS.md +14 -6
  20. package/docs/LEGACY-CLI-CROSSWALK.md +16 -6
  21. package/docs/PLUGIN-ISOLATION-CONTRACT.md +6 -4
  22. package/docs/ROADMAP.md +20 -6
  23. package/docs/RUNTIME-COMPAT-MATRIX.md +29 -16
  24. package/docs/STATE-DB-ACCESS-POLICY.md +43 -13
  25. package/docs/WORKFLOW-LIFECYCLE.md +105 -50
  26. package/hooks/README.md +10 -8
  27. package/hooks/active_task_context.py +105 -18
  28. package/hooks/context_spine.py +16 -4
  29. package/hooks/health_check.py +5 -4
  30. package/hooks/pre_stop_check.py +5 -2
  31. package/hooks/runtime_paths.py +396 -0
  32. package/hooks/subagent_tracker.py +5 -2
  33. package/hooks/workflow_checkpoint.py +16 -3
  34. package/hooks/workflow_context.py +11 -3
  35. package/hooks/workflow_resume.py +7 -4
  36. package/mcp-server/breadcrumb.cjs +20 -2
  37. package/mcp-server/lib/archive-journal.cjs +1026 -111
  38. package/mcp-server/lib/archive-mutation-worker.py +365 -0
  39. package/mcp-server/lib/artifact-registry.cjs +1127 -0
  40. package/mcp-server/lib/baseline-workflow.cjs +69 -28
  41. package/mcp-server/lib/change-packet.cjs +818 -0
  42. package/mcp-server/lib/change-workflow.cjs +932 -176
  43. package/mcp-server/lib/context-paths.cjs +142 -0
  44. package/mcp-server/lib/context-spine.cjs +511 -45
  45. package/mcp-server/lib/decision-dialogue.cjs +345 -3
  46. package/mcp-server/lib/delivery-transaction.cjs +471 -0
  47. package/mcp-server/lib/doctor-backup-worker.cjs +328 -0
  48. package/mcp-server/lib/doctor.cjs +401 -11
  49. package/mcp-server/lib/git-bootstrap.cjs +458 -47
  50. package/mcp-server/lib/init-project.cjs +240 -95
  51. package/mcp-server/lib/plan-publication-worker.cjs +830 -0
  52. package/mcp-server/lib/plan-store.cjs +700 -5
  53. package/mcp-server/lib/project-breadcrumb.cjs +23 -4
  54. package/mcp-server/lib/projector.cjs +211 -42
  55. package/mcp-server/lib/runtime-paths.cjs +1687 -0
  56. package/mcp-server/lib/safe-project-file.cjs +385 -0
  57. package/mcp-server/lib/spec-learning.cjs +28 -12
  58. package/mcp-server/lib/state-authority.cjs +19 -3
  59. package/mcp-server/lib/state-db.cjs +263 -9
  60. package/mcp-server/lib/state-ops.cjs +254 -50
  61. package/mcp-server/lib/task-ledger.cjs +1342 -0
  62. package/mcp-server/lib/telemetry.cjs +12 -3
  63. package/mcp-server/lib/workflow-state.cjs +610 -58
  64. package/mcp-server/server.cjs +423 -42
  65. package/orchestrator/daemon.cjs +2 -10
  66. package/orchestrator/parallel-orchestrator.cjs +314 -50
  67. package/orchestrator/planner/plan-builder.cjs +1 -1
  68. package/orchestrator/recovery.cjs +125 -7
  69. package/orchestrator/session-close-journal-worker.cjs +5 -0
  70. package/orchestrator/session-close-journal.cjs +1014 -0
  71. package/orchestrator/session-runner.cjs +679 -69
  72. package/orchestrator/worktree-manager.cjs +186 -35
  73. package/package.json +2 -3
  74. package/skills/cc-collab/SKILL.md +4 -1
  75. package/skills/codex-collab/SKILL.md +5 -2
  76. package/skills/ultra-change/SKILL.md +34 -8
  77. package/skills/ultra-deliver/SKILL.md +26 -11
  78. package/skills/ultra-dev/SKILL.md +52 -10
  79. package/skills/ultra-doctor/SKILL.md +16 -3
  80. package/skills/ultra-init/SKILL.md +22 -11
  81. package/skills/ultra-plan/SKILL.md +58 -18
  82. package/skills/ultra-research/SKILL.md +37 -35
  83. package/skills/ultra-review/SKILL.md +14 -8
  84. package/skills/ultra-status/SKILL.md +18 -9
  85. package/skills/ultra-test/SKILL.md +11 -5
  86. package/skills/ultra-think/SKILL.md +6 -2
  87. package/skills/ultra-think/references/decision-dialogue.md +17 -6
  88. package/skills/ultra-verify/SKILL.md +4 -1
  89. package/spec/cli-protocol.md +21 -7
  90. package/spec/mcp-tools.yaml +629 -44
  91. package/spec/schemas/change-delta.v1.schema.json +153 -0
  92. package/spec/schemas/context-file.v4.5.schema.json +1 -1
  93. package/spec/schemas/documentation-reconciliation.v1.schema.json +106 -0
  94. package/spec/schemas/mcp-tools.schema.json +1 -1
  95. package/spec/schemas/state-db.sql +51 -14
  96. package/spec/schemas/task-ledger.v1.schema.json +217 -0
  97. package/spec/schemas/tasks.v4.5.schema.json +1 -1
  98. package/ultra-tools/cli.cjs +3 -2
  99. package/ultra-tools/commands/db.cjs +76 -25
  100. package/ultra-tools/commands/migrate.cjs +1000 -82
  101. package/ultra-tools/commands/session.cjs +34 -8
  102. package/ultra-tools/commands/status.cjs +32 -6
  103. package/ultra-tools/commands/system.cjs +129 -22
  104. package/.ultra-template/tasks/contexts/TEMPLATE.md +0 -19
  105. package/commands/learn.md +0 -10
  106. package/orchestrator/skill-miner.cjs +0 -133
  107. package/output-styles/coding-vibes.md +0 -67
  108. package/output-styles/structural-thinking.md +0 -61
  109. package/skills/learn/SKILL.md +0 -58
@@ -11,10 +11,16 @@ host and project owner. It is the operational companion to
11
11
  |---|---|---|
12
12
  | Active host and owner | Product judgment, research content, implementation, review findings, and authorization for destructive or external effects | Durable workflow status or fabricated evidence digests |
13
13
  | Skill | One reusable procedure and its evidence requirements | Project state, static product doctrine, host-specific tool fiction |
14
- | MCP | IDs, valid transitions, hard recovery requirements, task contracts, evidence references, output hashes, and gate verdicts | Semantic route selection, research prose, code generation, memory, or model calls |
15
- | `.ultra/state.db` | Baseline, change, decision, task, workflow, session, event, incident, projection, and evidence authority | Prompts, transcripts, external memory, or code-graph payloads |
16
- | Generated JSON and Markdown | Read-only projections and durable artifacts | Independent lifecycle authority |
17
- | Hook | Compact DB-derived lifecycle observation, minimal event metadata, and projection protection | Generic engineering judgment, prompt/transcript capture, parallel lifecycle logs, or arbitrary edit blocking |
14
+ | MCP | IDs, valid transitions, hard recovery requirements, task contracts, evidence references, output hashes, and gate verdicts | Semantic route selection, research prose, code generation, general memory-provider payloads, or model calls |
15
+ | `.ultra/.runtime/state.db` | Checkout-local lifecycle, index, transition, freshness, and coordination authority for baseline, change, decision, task, workflow, session, event, incident, projection, and evidence references | Prompts, transcripts, general external-memory payloads, semantic prose, or code-graph payloads |
16
+ | `.ultra/tasks/tasks.json` | MCP-published Git checkpoint for portable baseline, Change, task-contract, dependency, and durable status records | Live sessions, leases, `in_progress` ownership, completion hashes, or a parallel write API |
17
+ | Digest-bound artifacts | Registered specification, research, Change, context, test, review, delivery, and verification bodies | Independent lifecycle state or content whose digest no longer matches |
18
+ | Generated projections and scratch | Checkout-local views below `.ultra/.runtime/` and temporary working material | Lifecycle, semantic, or evidence authority before supported promotion |
19
+ | Hook | Compact DB-derived lifecycle observation, minimal event metadata, and protection of MCP-owned checkpoint/projection paths | Generic engineering judgment, prompt/transcript capture, parallel lifecycle logs, or arbitrary edit blocking |
20
+
21
+ Together, `.ultra/` is project-local cross-session workflow memory. The detailed
22
+ artifact classes and promotion rules live in
23
+ [`ARTIFACT-AUTHORITY.md`](./ARTIFACT-AUTHORITY.md).
18
24
 
19
25
  Prompt input can supply facts, content paths, reasons, owner decisions, and
20
26
  evidence references. MCP reads the current repository and DB, validates those
@@ -71,8 +77,10 @@ signals. In a monorepo, the owner selects the repository scope; baseline
71
77
  worktree digests and accepted dirty files are restricted to that scope.
72
78
 
73
79
  Classification and readiness are separate. Initialization immediately creates
74
- or resumes `.ultra/state.db`, installs only the required scaffold, records the
75
- classification, and completes an `init` workflow after read-back verification. It
80
+ or resumes `.ultra/.runtime/state.db`, creates or imports the Git team checkpoint,
81
+ installs only the required scaffold, records the classification, and completes an
82
+ `init` workflow after read-back verification. A ready checkpoint baseline is held for
83
+ checkout-local revalidation. Init
76
84
  does not create a research run. A later explicit `ultra-research` invocation selects
77
85
  `full` for greenfield or `adoption` for brownfield, records coverage dispositions, and
78
86
  works toward baseline readiness. Empty templates are not an approved baseline.
@@ -144,11 +152,12 @@ traceability, slice kind, public seam, exact verification command, acceptance
144
152
  checks, context references, resolved documentation impact, owner, and valid
145
153
  dependencies.
146
154
 
147
- A semantic Change update marks all derived tasks stale. Clearing that marker requires
148
- one complete execution-contract rebind through `task.update`; a marker-only clear is
149
- rejected. MCP validates the resulting contract and appends
150
- `task_contract_reconciled` with the current Change authority digest before a new plan
151
- may converge.
155
+ A semantic Change update traverses registered provenance and consumer edges and marks
156
+ only reachable task, workflow, and artifact consumers stale. Unrelated tasks remain
157
+ current. Clearing a task marker requires one complete execution-contract rebind through
158
+ `task.update`; a marker-only clear is rejected. MCP validates the resulting contract
159
+ and appends `task_contract_reconciled` with the current Change authority digest before
160
+ a new plan may converge.
152
161
 
153
162
  A session process and a task have different status machines. Process exit zero closes
154
163
  the execution transport but leaves the task `in_progress` until development,
@@ -220,24 +229,41 @@ stores the conversation transcript.
220
229
 
221
230
  | Stage | Authoritative writes | Completion verification | Available continuation |
222
231
  |---|---|---|---|
223
- | `init` | Baseline classification/scope, Git bootstrap state, completed init run, initialization event, projection job | DB/schema opens, scaffold/projection and read-back succeed; existing Git is preserved or missing local Git is initialized | Explicitly chosen `research`, `status`, or `doctor`; an already-ready project may also enter `change` |
224
- | `research` | Accepted coverage dispositions, selected step evidence, normalized material decisions, optional artifact checkpoints, typed semantic records with source digests, immutable reports, output paths and SHA-256 digests | Every included coverage area is dispositioned; only executed/verified/reused areas require work evidence; synthesis binds current specifications and distillate; all material decisions and digests are current | Baseline record/convergence for initial research; bounded change research returns to its owning change |
225
- | baseline convergence | Spec/source/runtime refs, verification results, known failures, unknowns, gaps, branch/HEAD/worktree, approval | Full/adoption research complete; required discovery/product/architecture refs current; revision/worktree exact; blocking gaps resolved or explicitly accepted where allowed | `change` for every initial or daily outcome |
226
- | `change` | Complete Change Contract, profile/risk rationale, research disposition, intent/delta artifacts, and a completed capture run; a decision thread only when material intent remains unresolved | Intent, acceptance, recovery, classification, and research disposition are complete and bound to the baseline | Model recommends; owner selects or delegates bounded `research`, `plan`, current `dev`, `think`, or `status` from allowed transitions |
227
- | `plan` | Accepted planning posture, selected planning evidence, complete change-owned task rows, acceptance coverage matrix, and change-bound `.ultra/execution-plan.json`; approval only for a material owner decision | Every Change acceptance id is owned by a task; trace targets, ownership, dependencies, topology, task contracts, and exported digest match current authority | Any dependency-ready task may enter `dev` |
228
- | `dev` | Task/session transitions, real worktree, step evidence, immutable implementation context, completion/review references | Task completed; no live session; task contract unchanged; starting context and review artifacts valid; completion commits are integrated and remain ancestors of current HEAD | Next task, then aggregate `test` |
229
- | `test` | Immutable checking context, an explicit risk-selected verification profile, and `.ultra/reports/tests/<workflow-id>.json` | Selected dimensions and acceptance pass; every excluded dimension has a rationale; report change/task set, HEAD, worktree, context, commands, blockers, and digests agree | `review` when passing, otherwise resume `dev`/`test` |
230
- | `review` | Immutable review context, `task`/`change`/`plan` mode, risk-selected worker provenance, two mandatory specialist axes, and coordinated summary | Current diff/HEAD and context match; the complete worker roster is selected or skipped with rationale; completed workers match specialist artifacts; both axes complete; findings and axis verdicts derive the final verdict | `deliver` only from a passing `change` review, otherwise resume implementation or checking |
231
- | `deliver` | Convergence context, verified learning resolutions, semantic reconciliation manifest, local change archive, and immutable delivery report | Tasks/test/change-review are current; baseline semantic updates are anchored; archive and baseline transaction agree; the report contains no release action | Report local completion or start the next `change`; publish/deploy/push are separate explicitly authorized operations |
232
- | `status` | None | Reads doctor, baseline, workflows, breadcrumb, tasks, sessions, Git, and DB-referenced reports | Shows allowed transitions, any hard required transition, and a host-owned recommendation |
233
- | `doctor` | None by default; explicit repair writes only mechanical recovery state | Re-runs integrity, schema, workflow-output, projection, session, incident, archive, and install checks | Mechanically required recovery when unique; otherwise a set of safe recovery capabilities |
234
-
235
- Every mutating MCP operation appends an event and enqueues projection work when
236
- the corresponding read-only view can change. Projection failure is recorded as
232
+ | `init` | Baseline classification/scope, Git bootstrap state, completed init run, initialization event, empty or imported team checkpoint, projection job | DB/schema opens, scaffold/local projection/checkpoint and read-back succeed; existing Git is preserved or missing local Git is initialized; imported ready baseline is not trusted before local revalidation | Explicitly chosen `research`, `status`, or `doctor`; an already-ready project may also enter `change` |
233
+ | `research` | Accepted coverage dispositions, selected step evidence, normalized material decisions, optional artifact checkpoints, typed semantic records with source digests, immutable reports, output paths and SHA-256 digests | Every included coverage area is dispositioned; only executed/verified/reused areas require work evidence; baseline synthesis binds current specifications and distillate, while Change synthesis stays in its overlay; all material decisions and digests are current | Baseline record/convergence for initial research; bounded Change research records its delta and returns to plan |
234
+ | baseline convergence | Spec/source/runtime refs, verification results, known failures, unknowns, gaps, branch/HEAD/worktree, approval, and a published team checkpoint | Full/adoption research complete; required discovery/product/architecture refs current; revision/worktree exact; blocking gaps resolved or explicitly accepted where allowed | `change` for every initial or daily outcome |
235
+ | `change` | Complete Change Contract, profile/risk rationale, research disposition, isolated Change root, typed delta, completed capture run, and portable Change checkpoint; a decision thread only when material intent remains unresolved | Intent, acceptance, recovery, classification, research disposition, exact baseline anchors, and checkpoint digest are current | Model recommends; owner selects bounded `research` or direct `plan`; both routes converge on plan before development |
236
+ | `plan` | Accepted planning posture, immutable `plan/planning` context, selected planning evidence, complete change-owned task rows, acceptance coverage matrix, deterministic `<artifact_root>/plan.json` plus `plan.md`, and published task contracts; approval only for a material owner decision | Every Change acceptance id is owned by a task; trace targets, ownership, dependencies, topology, task contracts, planning-context binding, exported digests, and checkpoint generation match current authority | Any dependency-ready task may enter `dev` |
237
+ | `dev` | Task/session transitions, real worktree, step evidence, immutable implementation context, completion/review references, and published durable task transitions | Task completed; no live session; task contract unchanged; starting context and review artifacts valid; the single completion commit is integrated and remains an ancestor of current HEAD; its hash is backfilled locally without another commit | Next task, then aggregate `test` |
238
+ | `test` | Immutable checking context, an explicit risk-selected verification profile, and `<artifact_root>/test/<workflow-id>/report.json` | Selected dimensions and exact Change acceptance ids pass; every excluded dimension has a rationale; report change/task set, HEAD, worktree, context, commands, blockers, and digests agree | `review` when passing, otherwise resume `dev`/`test` |
239
+ | `review` | Immutable review context plus risk-selected specialist and summary artifacts below `<artifact_root>/review/<workflow-id>/` | Current diff/HEAD and context match; the complete worker roster is selected or skipped with rationale; completed workers match specialist artifacts; both axes complete; findings and axis verdicts derive the final verdict | `deliver` only from a passing `change` review, otherwise resume implementation or checking |
240
+ | `deliver` | Convergence context, typed delta, documentation reconciliation, recoverable overlay transaction, self-contained archive, and immutable delivery report | Tasks/test/change-review and acceptance are current; every before/after digest and baseline anchor is current; the archive transaction is complete; the report contains no release action | Report local completion or start the next `change`; publish/deploy/push are separate explicitly authorized operations |
241
+ | `status` | None | Reads doctor, team-checkpoint condition, baseline, workflows, breadcrumb, tasks, sessions, Git, and DB-referenced reports | Shows allowed transitions, any hard required transition, and a host-owned recommendation |
242
+ | `doctor` | None by default; explicit repair writes only mechanical recovery state | Re-runs integrity, schema, workflow-output, local projection, team-checkpoint, session, incident, archive, and install checks without choosing import/publish conflict resolution | Mechanically required recovery when unique; otherwise a set of safe recovery capabilities |
243
+
244
+ Every mutating MCP operation appends an event and enqueues local projection work when
245
+ the corresponding checkout-local read-only view can change. Projection failure is recorded as
237
246
  a retryable incident; it does not silently convert a failed write into success.
247
+ Semantic handoff operations separately publish the Git team checkpoint.
238
248
  `task.append_event` accepts only non-authoritative observations. Lifecycle events are
239
249
  emitted by their owning DB mutation and never act as a substitute state transition.
240
250
 
251
+ ### Team handoff checkpoint
252
+
253
+ The Git checkpoint is intentionally lower-frequency than SQLite. It publishes accepted
254
+ baseline, Change, plan, task-contract, and durable task-status boundaries; it does not
255
+ mirror heartbeats, leases, active processes, telemetry, or provisional completion
256
+ hashes. On MCP startup or explicit post-pull import, the receiving checkout validates
257
+ checkpoint ancestry and record digests. Clean baseline, Change, and task records
258
+ fast-forward independently. Concurrent edits to the same record or a remote edit to a
259
+ locally active task stop without partial import.
260
+
261
+ A checkpoint can restore portable project intent after clone, but cannot establish
262
+ checkout truth by itself. An imported ready baseline becomes a local adoption/draft
263
+ with `team-ledger-revalidation-required`; current scope content, HEAD, verification,
264
+ known failures, and approval must converge again. Because baseline content hashing
265
+ excludes `.ultra/`, committing the checkpoint cannot make its own baseline stale.
266
+
241
267
  ## 5. Human-agent alignment lifecycle
242
268
 
243
269
  The host first reads `decision.list` and resumes matching authority. It starts a new
@@ -256,26 +282,31 @@ thread only for a new material decision cluster. Before asking, it must:
256
282
  6. normalize the owner response with `decision.resolve`, explicit reversible
257
283
  delegation with `decision.delegate`, or a consequence-bearing deferral with
258
284
  `decision.defer`;
259
- 7. call `decision.complete` when normalized state is settled, or prepare a compact
285
+ 7. apply accepted intent through the owning MCP operation or digest-bound artifact;
286
+ 8. read the resulting authority back and record typed `applied_refs` when another
287
+ authority changed;
288
+ 9. call `decision.complete` when normalized state is settled, or prepare a compact
260
289
  checkpoint only when a material decision cluster changes a durable contract and
261
290
  interruption recovery needs an artifact-bound boundary.
262
291
 
263
- The shared semantic flow is `inspect -> suggest -> ask if unresolved -> normalize ->
264
- persist`. Claude Code and Kimi Code use `AskUserQuestion`, Codex uses
292
+ The shared semantic flow is `inspect -> suggest -> host-native ask -> normalize ->
293
+ persist -> apply -> read back`. The ask is skipped only when current explicit intent
294
+ already resolves the material choice. Claude Code and Kimi Code use `AskUserQuestion`, Codex uses
265
295
  `request_user_input` when its current mode exposes it, and OpenCode uses `question`
266
296
  when permitted. Every host falls back to one concise direct question when normal
267
297
  conversation is still allowed. If the current host mode forbids interaction entirely,
268
298
  the choice remains unanswered and route-dependent writes stop. A dismissed question
269
299
  also remains unanswered. The DB trusts a normalized persisted result as current
270
300
  authority across sessions; it does not store or verify a UI receipt, raw prompt, or
271
- transcript.
301
+ transcript. Breadcrumb and decision reads recall completed normalized intent, so a new
302
+ host session can continue without replaying the dialogue.
272
303
 
273
304
  `ultra-think` owns this interaction protocol. `ultra-research`, `ultra-change`, and
274
305
  `ultra-plan` invoke it at their decision boundaries. `ultra-dev`, `ultra-test`,
275
306
  `ultra-review`, and `ultra-deliver` stop and route back to the same thread when new
276
307
  owner authority is required; they never answer on the owner's behalf. `ultra-status`
277
- shows only the current decision and transition set, while `ultra-doctor` diagnoses
278
- stale checkpoint artifacts and recovery state.
308
+ shows current unresolved decisions, relevant accepted intent, and the transition set,
309
+ while `ultra-doctor` diagnoses stale checkpoint artifacts and recovery state.
279
310
 
280
311
  When only a bound artifact changes, the same resolved thread is prepared and approved
281
312
  again against the current digest; this is checkpoint renewal, not a fabricated decision
@@ -289,37 +320,54 @@ opens one replacement.
289
320
  - the bound baseline/change/task identity;
290
321
  - a role and lifecycle gate;
291
322
  - DB-backed task outcome, public seam, verification command, and required refs;
323
+ - the selected task's bounded dependency/integration neighborhood rather than every
324
+ unrelated task;
325
+ - the task-context contract: purpose, why, constraints, non-goals, target seams/files,
326
+ pattern refs, acceptance, documentation impact, recovery, and drift definition;
292
327
  - local file hashes, current HEAD, branch, and worktree digest;
293
328
  - optional metadata-only external memory or graph references;
294
- - advisory file/token/context-share budgets;
329
+ - advisory file/token/context-share budgets, including inline Change/task authority;
295
330
  - the current Change and task authority digests;
296
331
  - readiness blockers, `allowed_transitions`, and a `required_transition` only for a
297
332
  unique hard-recovery path.
298
333
 
334
+ Compilation is pure with respect to accepted Change authority. Provider references are
335
+ updated only through `change.update`; they cannot be smuggled into `change.context`.
336
+ Context references retain `expected_digest`, `anchor`, `scope`, and
337
+ `freshness_policy`. `digest` requires byte-current content, `existence` allows an
338
+ implementation target to change while remaining present, and `advisory` reports drift
339
+ without blocking.
340
+
299
341
  Critical stage workflows bind a matching snapshot as a durable output:
300
342
 
301
343
  | Workflow | Required role | Required gate |
302
344
  |---|---|---|
345
+ | `plan` | `plan` | `planning` |
303
346
  | `dev` | `implement` | `implementation` |
304
347
  | `test` | `check` | `verification` |
305
348
  | `review` | `review` | `review` |
306
349
  | `deliver` | `check` | `convergence` |
307
350
 
308
- The snapshot path and digest are then carried into test, review, and delivery
309
- reports. This prevents a later Prompt from claiming evidence gathered under a
310
- different context. File and token budgets warn; they do not block legitimate
311
- work. Missing authority, required refs, task contracts, outputs, required owner
312
- decisions, or
313
- current gate evidence do block.
351
+ Every lookup is exact on `change_id + task_id + role + gate`. The snapshot path and
352
+ digest are carried into plan, test, review, and delivery artifacts. `plan.export`
353
+ writes only the owning Change's `plan.json` and deterministic `plan.md`, and binds the
354
+ exact planning snapshot and digest to both the artifact registry and `verify-plan`.
355
+ The legacy global `.ultra/execution-plan.json` is read-only migration compatibility,
356
+ not current authority. These rules prevent a later Prompt or a different role packet
357
+ from claiming evidence gathered under another context. Referenced file content remains
358
+ lazy; only metadata and bounded task authority are inline. File and token budgets warn;
359
+ they do not block legitimate work. Missing authority, required refs, stale
360
+ digest-bound refs, task contracts, outputs, required owner decisions, or current gate
361
+ evidence do block.
314
362
 
315
363
  ## 7. Invalidation rules
316
364
 
317
365
  - Changing a task contract invalidates contexts and gates that depended on the
318
366
  former contract.
319
367
  - Changing accepted Change intent, contract, classification, research disposition,
320
- provider evidence, or documentation impact marks all derived tasks stale and
321
- invalidates compiled contexts. Planning or task reconciliation must explicitly
322
- clear staleness before execution.
368
+ provider evidence, or documentation impact invalidates only transitive registered
369
+ consumers. Planning or task reconciliation must explicitly refresh affected
370
+ authority before execution.
323
371
  - Changing required source/spec content invalidates the recorded output or
324
372
  context digest.
325
373
  - Changing a research semantic source invalidates that workflow even when its immutable
@@ -333,10 +381,17 @@ current gate evidence do block.
333
381
  overwrite historical evidence.
334
382
  - `.ultra` workflow artifacts are excluded from application-worktree drift, but
335
383
  their own recorded SHA-256 digests are still authoritative.
336
- - Generated `tasks.json` and task-context headers are projections. Manual edits
337
- are overwritten and never repair DB authority.
384
+ - Generated `.ultra/.runtime/projections/tasks.json` and complete runtime task-context
385
+ files are local projections. Manual edits are overwritten and never repair DB
386
+ authority.
387
+ - `.ultra/tasks/tasks.json` is a tracked MCP checkpoint, not a local projection.
388
+ Its full and per-record digests reject manual edits; publish/import performs typed
389
+ fast-forward or conflict handling.
338
390
  - A changed checkpoint artifact digest or superseded decision invalidates the linked
339
391
  decision checkpoint and blocks matching workflow advancement until reconfirmed.
392
+ - `workflow.revise` creates a candidate without deleting the completed prior run.
393
+ `workflow.supersede` promotes only a completed matching candidate, preserves both
394
+ histories, and invalidates only the prior run's transitive registered consumers.
340
395
 
341
396
  ## 8. Entry flows
342
397
 
@@ -347,7 +402,7 @@ ultra-init -> Git/scaffold/authority verification -> init completed
347
402
  -> explicit ultra-research -> suggested route -> owner-selected accepted coverage
348
403
  -> selected evidence work
349
404
  -> local checkpoint when Git is unborn -> baseline approval
350
- -> ultra-change -> optional bounded research/plan -> dev -> risk-selected test/review
405
+ -> ultra-change -> optional bounded research -> typed delta -> plan -> dev -> risk-selected test/review
351
406
  -> local deliver/archive
352
407
  ```
353
408
 
@@ -357,7 +412,7 @@ ultra-init -> Git/scaffold/authority verification -> init completed
357
412
  ultra-init -> preserve Git/classify brownfield -> init completed
358
413
  -> explicit adoption research -> suggested route -> owner-selected accepted coverage
359
414
  -> selected characterization/known-red evidence -> gap ledger -> owner approval
360
- -> first ultra-change -> optional bounded research/plan -> dev -> test/review -> deliver
415
+ -> first ultra-change -> optional bounded research -> typed delta -> plan -> dev -> test/review -> deliver
361
416
  ```
362
417
 
363
418
  Adoption records the system that exists. It does not force the owner to recreate
@@ -377,9 +432,9 @@ Migration preserves prior files and rows but never carries old approval forward.
377
432
 
378
433
  ```text
379
434
  ultra-status -> ultra-change intent capture
380
- -> model recommends; owner selects or delegates bounded research, plan, current task,
381
- think, or status
382
- -> dev -> risk-selected test -> review -> deliver -> reconciled baseline
435
+ -> model recommends; owner selects bounded research or direct plan
436
+ -> typed delta -> plan -> dev -> risk-selected test -> review
437
+ -> documentation reconciliation -> atomic deliver -> reconciled baseline
383
438
  ```
384
439
 
385
440
  Quick changes shorten the artifact burden only where the machine contract allows;
@@ -392,9 +447,9 @@ evidence rather than bypassing them.
392
447
  | Entry | Owns | Normal handoff |
393
448
  |---|---|---|
394
449
  | `ultra-init` | classification, scope, Git/scaffold bootstrap, and init verification | stops completed; exposes research/status/doctor and any already-valid change capability |
395
- | `ultra-research` | coverage disposition, selected evidence acquisition, synthesis, and material research decisions | baseline convergence or return to the owning change |
450
+ | `ultra-research` | coverage disposition, selected evidence acquisition, synthesis, and material research decisions | baseline convergence or Change delta then plan |
396
451
  | `ultra-think` | one material owner decision or read-only diagnosis | returns to the invoking capability after any needed checkpoint |
397
- | `ultra-change` | outcome capture, Change Contract, risk/research routing | model recommends; owner selects or delegates research, plan, current dev work, think, or status |
452
+ | `ultra-change` | outcome capture, Change Contract, isolated overlay, typed delta, and risk/research routing | model recommends; owner selects research or direct plan; development is never a direct handoff |
398
453
  | `ultra-plan` | task contracts, dependencies, acceptance coverage, optional material approval | any dependency-ready task through `ultra-dev` |
399
454
  | `ultra-dev` | one task/session vertical slice and focused review | next `ultra-dev` task or aggregate `ultra-test` |
400
455
  | `ultra-test` | risk-selected change acceptance and verification profile | `ultra-review` on pass, `ultra-dev`/`ultra-test` on failure |
package/hooks/README.md CHANGED
@@ -1,24 +1,26 @@
1
1
  # Ultra Builder Pro workflow hooks
2
2
 
3
3
  These hooks observe only Ultra-owned state. Session health/context recognizes an initialized
4
- `.ultra/state.db` and active continuous changes. Direct projection writes remain blocked;
5
- context, compact, stop, and subagent lifecycle behavior is recovery-oriented and does not turn
6
- advisory workflow conditions into refusal gates.
4
+ `.ultra/.runtime/state.db` and active continuous changes. Direct writes to the MCP-owned Git
5
+ checkpoint and checkout-local projections remain blocked; context, compact, stop, and subagent
6
+ lifecycle behavior is recovery-oriented and does not turn advisory workflow conditions into
7
+ refusal gates.
7
8
 
8
9
  | Lifecycle | Hook | Purpose |
9
10
  |---|---|---|
10
11
  | Session start | `health_check.py` | Read-only integrity, incident, projection, session, and change-artifact checks |
11
12
  | Shared helper | `context_spine.py` | Read the latest role/gate/readiness snapshot from state.db and derive one compact breadcrumb |
12
- | Session start | `workflow_context.py` | Inject the DB-derived breadcrumb without intent or provider payloads |
13
- | Before edit | `active_task_context.py` | Protect `tasks.json` and restate the same DB-derived task breadcrumb |
13
+ | Session start | `workflow_context.py` | Inject the DB-derived breadcrumb with bounded normalized accepted intent, never raw interaction or provider payloads |
14
+ | Before edit | `active_task_context.py` | Protect `.ultra/tasks/tasks.json` (Git team checkpoint) and `.ultra/.runtime/projections/tasks.json` (local view), then restate the same DB-derived task breadcrumb |
14
15
  | Before compact | `workflow_checkpoint.py` | Validate and atomically save a minimal workflow checkpoint |
15
16
  | After compact/resume | `workflow_resume.py` | Prefer the DB breadcrumb; restore the minimal file checkpoint only when no active change owns recovery |
16
17
  | Stop | `pre_stop_check.py` | Report an incomplete workflow boundary and allow stop |
17
18
  | Subagent lifecycle | `subagent_tracker.py` | Append minimal start/stop metadata to the authoritative DB event stream |
18
19
 
19
- The plugin deliberately does not capture prompts, tool observations, transcripts, summaries, or
20
- cross-session memory or code-graph content. Generic command blocking and post-edit policy are
21
- user/repository governance. Persistent Memory/graph content belongs to separately installed providers.
20
+ The plugin deliberately does not capture prompts, tool observations, transcripts, summaries, general
21
+ conversational memory, or code-graph payloads. It does retain project-local Ultra workflow memory in
22
+ `.ultra/`. Generic command blocking and post-edit policy are user/repository governance. General
23
+ memory and graph content belongs to separately installed providers.
22
24
 
23
25
  `subagent_tracker.py` passes only agent id/type and the host session id to the bundled
24
26
  `hook-event.cjs` helper. The helper binds the current change/task and appends
@@ -1,30 +1,77 @@
1
1
  #!/usr/bin/env python3
2
- """Protect Ultra projections and restate an active task boundary before edits."""
2
+ """Protect Ultra managed task files and restate the active workflow boundary."""
3
3
 
4
4
  import json
5
5
  import sys
6
6
  from pathlib import Path
7
7
 
8
- from context_spine import ContextSpineError, find_root, read_breadcrumb, render_breadcrumb
8
+ from context_spine import (
9
+ ContextSpineError,
10
+ find_root,
11
+ read_breadcrumb,
12
+ render_breadcrumb,
13
+ )
9
14
 
10
- TASKS_PROJECTION = Path(".ultra/tasks/tasks.json")
15
+ TEAM_TASK_LEDGER = Path(".ultra/tasks/tasks.json")
16
+ LIVE_TASK_PROJECTION = Path(".ultra/.runtime/projections/tasks.json")
17
+ PROTECTED_TASK_FILES = (TEAM_TASK_LEDGER, LIVE_TASK_PROJECTION)
11
18
 
12
19
 
13
- def targets_tasks_projection(data: dict, root: Path) -> bool:
20
+ def tool_paths(data: dict, start: Path):
21
+ """Yield absolute tool targets without assuming they belong to ``start``."""
14
22
  tool_input = data.get("tool_input")
15
23
  if not isinstance(tool_input, dict):
16
- return False
24
+ return
17
25
  for key in ("file_path", "filePath", "filepath", "path"):
18
26
  value = tool_input.get(key)
19
27
  if not isinstance(value, str) or not value.strip():
20
28
  continue
21
29
  candidate = Path(value)
22
- resolved = candidate.resolve() if candidate.is_absolute() else (root / candidate).resolve()
23
- if resolved == (root / TASKS_PROJECTION).resolve():
30
+ yield candidate.resolve() if candidate.is_absolute() else (start / candidate).resolve()
31
+
32
+
33
+ def protected_root_for_target(target: Path) -> Path | None:
34
+ """Return the project root for an exact MCP-managed task file."""
35
+ parts = target.parts
36
+ for relative in PROTECTED_TASK_FILES:
37
+ suffix = relative.parts
38
+ if len(parts) >= len(suffix) and parts[-len(suffix):] == suffix:
39
+ return Path(*parts[:-len(suffix)])
40
+ return None
41
+
42
+
43
+ def targets_managed_task_file(data: dict, root: Path) -> bool:
44
+ for resolved in tool_paths(data, root):
45
+ if any(resolved == (root / relative).resolve() for relative in PROTECTED_TASK_FILES):
24
46
  return True
25
47
  return False
26
48
 
27
49
 
50
+ def managed_file_denial(reason: str) -> dict:
51
+ return {"hookSpecificOutput": {
52
+ "hookEventName": "PreToolUse",
53
+ "permissionDecision": "deny",
54
+ "permissionDecisionReason": reason,
55
+ }}
56
+
57
+
58
+ def conflicted_managed_root(data: dict, start: Path) -> Path | None:
59
+ for candidate in (start, *start.parents):
60
+ if not (candidate / ".ultra").exists():
61
+ continue
62
+ if targets_managed_task_file(data, candidate):
63
+ return candidate
64
+ return None
65
+
66
+
67
+ def managed_roots(data: dict, start: Path):
68
+ """Yield initialized project roots derived from every resolved tool target."""
69
+ for target in tool_paths(data, start):
70
+ root = protected_root_for_target(target)
71
+ if root is not None and (root / ".ultra").exists():
72
+ yield root
73
+
74
+
28
75
  def main() -> None:
29
76
  try:
30
77
  data = json.loads(sys.stdin.read() or "{}")
@@ -32,20 +79,60 @@ def main() -> None:
32
79
  except json.JSONDecodeError as exc:
33
80
  print(f"[active_task_context] invalid hook input: {exc}", file=sys.stderr)
34
81
  data = {}
35
- root = find_root(Path(data.get("cwd") or Path.cwd()).resolve())
82
+ start = Path(data.get("cwd") or Path.cwd()).resolve()
83
+ # An absolute tool target carries its own project boundary. Resolve and
84
+ # protect that authority before consulting cwd, because hooks may run from
85
+ # a host-owned temporary directory or another repository.
86
+ for target_root in managed_roots(data, start):
87
+ try:
88
+ target_authority = find_root(target_root)
89
+ except ContextSpineError as exc:
90
+ print(json.dumps(managed_file_denial(
91
+ "Refusing a direct write to an MCP-managed Ultra task file while the "
92
+ f"runtime authority is conflicted: {exc}. Resolve the "
93
+ "state.db conflict with ultra-doctor before retrying the owning "
94
+ "MCP operation."
95
+ )))
96
+ return
97
+ if target_authority is None:
98
+ continue
99
+ print(json.dumps(managed_file_denial(
100
+ "Refusing a direct write to an MCP-managed Ultra task file. "
101
+ ".ultra/tasks/tasks.json is the MCP-published team checkpoint and "
102
+ ".ultra/.runtime/projections/tasks.json is the checkout-local DB view. "
103
+ "Use the Ultra MCP task or task.ledger tools."
104
+ )))
105
+ return
106
+
107
+ try:
108
+ root = find_root(start)
109
+ except ContextSpineError as exc:
110
+ print(
111
+ f"[active_task_context] cannot resolve Ultra root: {exc}",
112
+ file=sys.stderr,
113
+ )
114
+ # Ordinary context injection remains fail-open. A direct write to a
115
+ # known managed task file is different: an authority conflict means the
116
+ # hook cannot prove which DB owns the publish or projection operation.
117
+ if conflicted_managed_root(data, start) is not None:
118
+ print(json.dumps(managed_file_denial(
119
+ "Refusing a direct write to an MCP-managed Ultra task file while the "
120
+ f"runtime authority is conflicted: {exc}. Resolve the "
121
+ "state.db conflict with ultra-doctor before retrying the owning "
122
+ "MCP operation."
123
+ )))
124
+ return
125
+ root = None
36
126
  if root is None:
37
127
  print(json.dumps({}))
38
128
  return
39
- if targets_tasks_projection(data, root):
40
- print(json.dumps({"hookSpecificOutput": {
41
- "hookEventName": "PreToolUse",
42
- "permissionDecision": "deny",
43
- "permissionDecisionReason": (
44
- "Refusing a direct write to the .ultra/tasks/tasks.json projection. "
45
- ".ultra/state.db is authoritative; use the Ultra MCP task tools and "
46
- "run ultra-doctor when state or projection health is degraded."
47
- ),
48
- }}))
129
+ if targets_managed_task_file(data, root):
130
+ print(json.dumps(managed_file_denial(
131
+ "Refusing a direct write to an MCP-managed Ultra task file. "
132
+ ".ultra/tasks/tasks.json is the MCP-published team checkpoint and "
133
+ ".ultra/.runtime/projections/tasks.json is the checkout-local DB view. "
134
+ "Use the Ultra MCP task or task.ledger tools."
135
+ )))
49
136
  return
50
137
  try:
51
138
  breadcrumb = read_breadcrumb(root)
@@ -5,8 +5,11 @@ import json
5
5
  import os
6
6
  import shutil
7
7
  import subprocess
8
+ import sys
8
9
  from pathlib import Path
9
10
 
11
+ from runtime_paths import RuntimePathError, find_project_root
12
+
10
13
 
11
14
  class ContextSpineError(RuntimeError):
12
15
  """The canonical breadcrumb helper could not be executed or decoded."""
@@ -21,10 +24,19 @@ class Breadcrumb(dict):
21
24
 
22
25
 
23
26
  def find_root(start: Path):
24
- for root in (start, *start.parents):
25
- if (root / ".ultra" / "state.db").is_file():
26
- return root
27
- return None
27
+ try:
28
+ return find_project_root(start)
29
+ except RuntimePathError as exc:
30
+ raise ContextSpineError(str(exc)) from exc
31
+
32
+
33
+ def find_root_for_hook(start: Path, hook_name: str):
34
+ """Fail open at a hook boundary while preserving path-conflict evidence."""
35
+ try:
36
+ return find_root(start)
37
+ except ContextSpineError as exc:
38
+ print(f"[{hook_name}] cannot resolve Ultra root: {exc}", file=sys.stderr)
39
+ return None
28
40
 
29
41
 
30
42
  def _helper_path() -> Path:
@@ -6,7 +6,8 @@ import sqlite3
6
6
  import sys
7
7
  from pathlib import Path
8
8
 
9
- from context_spine import ContextSpineError, find_root, read_breadcrumb
9
+ from context_spine import ContextSpineError, find_root_for_hook, read_breadcrumb
10
+ from runtime_paths import state_db_path
10
11
 
11
12
 
12
13
  REQUIRED_TABLES = {
@@ -44,7 +45,7 @@ def has_active_workflow(db_path: Path) -> bool:
44
45
 
45
46
 
46
47
  def inspect(root: Path) -> dict:
47
- db_path = root / ".ultra" / "state.db"
48
+ db_path = state_db_path(root)
48
49
  report = {"status": "healthy", "project": str(root), "checks": {}}
49
50
  issues = []
50
51
  if not db_path.is_file():
@@ -183,11 +184,11 @@ def inspect(root: Path) -> dict:
183
184
  def main() -> None:
184
185
  data = hook_input()
185
186
  start = Path(data.get("cwd") or Path.cwd()).resolve()
186
- root = find_root(start)
187
+ root = find_root_for_hook(start, "health_check")
187
188
  if root is None:
188
189
  print(json.dumps({}))
189
190
  return
190
- if not has_active_workflow(root / ".ultra" / "state.db"):
191
+ if not has_active_workflow(state_db_path(root)):
191
192
  print(json.dumps({}))
192
193
  return
193
194
  report = inspect(root)
@@ -5,7 +5,7 @@ import json
5
5
  import sys
6
6
  from pathlib import Path
7
7
 
8
- from context_spine import ContextSpineError, find_root, read_breadcrumb
8
+ from context_spine import ContextSpineError, find_root_for_hook, read_breadcrumb
9
9
 
10
10
 
11
11
  def allow_stop() -> None:
@@ -24,7 +24,10 @@ def main() -> None:
24
24
  if hook_data.get("stop_hook_active", False):
25
25
  allow_stop()
26
26
  return
27
- root = find_root(Path(hook_data.get("cwd") or Path.cwd()).resolve())
27
+ root = find_root_for_hook(
28
+ Path(hook_data.get("cwd") or Path.cwd()).resolve(),
29
+ "pre_stop_check",
30
+ )
28
31
  if root is None:
29
32
  allow_stop()
30
33
  return