ultra-builder-pro-cli 0.19.1 → 0.21.1
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.
- package/.ultra-template/docs/research/README.md +26 -5
- package/.ultra-template/specs/discovery.md +1 -1
- package/.ultra-template/tasks/tasks.json +1 -1
- package/CHANGELOG.md +90 -1
- package/README.md +62 -29
- package/adapters/_shared/codex-assets.cjs +69 -11
- package/adapters/_shared/interaction-contract.cjs +60 -5
- package/adapters/_shared/runtime-assets.cjs +41 -1
- package/adapters/claude.js +7 -5
- package/adapters/codex.js +1 -1
- package/adapters/kimi.js +2 -8
- package/adapters/opencode.js +30 -28
- package/bin/orchestrator.js +64 -24
- package/commands/ultra-research.md +1 -1
- package/docs/AGENT-CONTEXT.md +79 -45
- package/docs/ARCHITECTURE.md +75 -38
- package/docs/ARTIFACT-AUTHORITY.md +234 -0
- package/docs/DECISIONS.md +20 -10
- package/docs/LEGACY-CLI-CROSSWALK.md +15 -11
- package/docs/PLUGIN-ISOLATION-CONTRACT.md +4 -3
- package/docs/ROADMAP.md +21 -6
- package/docs/RUNTIME-COMPAT-MATRIX.md +30 -13
- package/docs/STATE-DB-ACCESS-POLICY.md +11 -9
- package/docs/WORKFLOW-LIFECYCLE.md +105 -54
- package/hooks/README.md +6 -5
- package/hooks/active_task_context.py +97 -12
- package/hooks/context_spine.py +16 -4
- package/hooks/health_check.py +5 -4
- package/hooks/pre_stop_check.py +5 -2
- package/hooks/runtime_paths.py +396 -0
- package/hooks/subagent_tracker.py +5 -2
- package/hooks/workflow_checkpoint.py +16 -3
- package/hooks/workflow_context.py +11 -3
- package/hooks/workflow_resume.py +7 -4
- package/mcp-server/breadcrumb.cjs +20 -2
- package/mcp-server/lib/archive-journal.cjs +1026 -111
- package/mcp-server/lib/archive-mutation-worker.py +365 -0
- package/mcp-server/lib/artifact-registry.cjs +1126 -0
- package/mcp-server/lib/baseline-workflow.cjs +9 -4
- package/mcp-server/lib/change-packet.cjs +818 -0
- package/mcp-server/lib/change-workflow.cjs +932 -176
- package/mcp-server/lib/context-paths.cjs +111 -0
- package/mcp-server/lib/context-spine.cjs +511 -45
- package/mcp-server/lib/decision-dialogue.cjs +427 -12
- package/mcp-server/lib/delivery-transaction.cjs +471 -0
- package/mcp-server/lib/doctor-backup-worker.cjs +328 -0
- package/mcp-server/lib/doctor.cjs +375 -12
- package/mcp-server/lib/git-bootstrap.cjs +459 -47
- package/mcp-server/lib/init-project.cjs +190 -95
- package/mcp-server/lib/plan-publication-worker.cjs +830 -0
- package/mcp-server/lib/plan-store.cjs +700 -5
- package/mcp-server/lib/project-breadcrumb.cjs +23 -4
- package/mcp-server/lib/projector.cjs +174 -40
- package/mcp-server/lib/runtime-paths.cjs +1687 -0
- package/mcp-server/lib/safe-project-file.cjs +385 -0
- package/mcp-server/lib/spec-learning.cjs +28 -12
- package/mcp-server/lib/state-db.cjs +397 -13
- package/mcp-server/lib/state-ops.cjs +248 -49
- package/mcp-server/lib/telemetry.cjs +12 -3
- package/mcp-server/lib/workflow-state.cjs +614 -62
- package/mcp-server/server.cjs +282 -33
- package/orchestrator/daemon.cjs +2 -10
- package/orchestrator/parallel-orchestrator.cjs +314 -50
- package/orchestrator/planner/plan-builder.cjs +1 -1
- package/orchestrator/recovery.cjs +125 -7
- package/orchestrator/session-close-journal-worker.cjs +5 -0
- package/orchestrator/session-close-journal.cjs +1014 -0
- package/orchestrator/session-runner.cjs +679 -69
- package/orchestrator/worktree-manager.cjs +186 -35
- package/package.json +2 -3
- package/skills/cc-collab/SKILL.md +4 -1
- package/skills/codex-collab/SKILL.md +5 -2
- package/skills/ultra-change/SKILL.md +38 -13
- package/skills/ultra-deliver/SKILL.md +23 -11
- package/skills/ultra-dev/SKILL.md +33 -6
- package/skills/ultra-doctor/SKILL.md +6 -2
- package/skills/ultra-init/SKILL.md +4 -2
- package/skills/ultra-plan/SKILL.md +68 -18
- package/skills/ultra-research/SKILL.md +45 -32
- package/skills/ultra-review/SKILL.md +9 -5
- package/skills/ultra-status/SKILL.md +9 -4
- package/skills/ultra-test/SKILL.md +15 -7
- package/skills/ultra-think/SKILL.md +6 -0
- package/skills/ultra-think/references/decision-dialogue.md +61 -14
- package/skills/ultra-verify/SKILL.md +4 -1
- package/spec/cli-protocol.md +19 -7
- package/spec/mcp-tools.yaml +531 -46
- package/spec/schemas/change-delta.v1.schema.json +153 -0
- package/spec/schemas/documentation-reconciliation.v1.schema.json +106 -0
- package/spec/schemas/mcp-tools.schema.json +1 -1
- package/spec/schemas/state-db.sql +57 -17
- package/spec/schemas/tasks.v4.5.schema.json +1 -1
- package/ultra-tools/cli.cjs +3 -2
- package/ultra-tools/commands/db.cjs +76 -25
- package/ultra-tools/commands/migrate.cjs +995 -80
- package/ultra-tools/commands/session.cjs +34 -8
- package/ultra-tools/commands/status.cjs +34 -7
- package/ultra-tools/commands/system.cjs +129 -22
- package/commands/learn.md +0 -10
- package/orchestrator/skill-miner.cjs +0 -133
- package/output-styles/coding-vibes.md +0 -67
- package/output-styles/structural-thinking.md +0 -61
- package/skills/learn/SKILL.md +0 -58
|
@@ -11,11 +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` |
|
|
16
|
-
|
|
|
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` | 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
|
+
| Digest-bound artifacts | Registered specification, research, Change, context, test, review, delivery, and verification bodies | Independent lifecycle state or content whose digest no longer matches |
|
|
17
|
+
| Generated projections and scratch | Human-readable views and temporary working material | Lifecycle, semantic, or evidence authority before supported promotion |
|
|
17
18
|
| 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 |
|
|
18
19
|
|
|
20
|
+
Together, `.ultra/` is project-local cross-session workflow memory. The detailed
|
|
21
|
+
artifact classes and promotion rules live in
|
|
22
|
+
[`ARTIFACT-AUTHORITY.md`](./ARTIFACT-AUTHORITY.md).
|
|
23
|
+
|
|
19
24
|
Prompt input can supply facts, content paths, reasons, owner decisions, and
|
|
20
25
|
evidence references. MCP reads the current repository and DB, validates those
|
|
21
26
|
inputs, hashes outputs, and derives status. Prompt input cannot override a task's
|
|
@@ -25,9 +30,10 @@ as MCP authority.
|
|
|
25
30
|
|
|
26
31
|
Load-bearing owner choices are normalized through `decision.*`; Prompt prose is not
|
|
27
32
|
durable authority. The host acquires observable facts autonomously, exposes one
|
|
28
|
-
current question, and stops. A workflow cannot advance while a matching decision
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
current question, and stops. A workflow cannot advance while a matching decision has
|
|
34
|
+
an unanswered blocking question, a blocking deferral, a prepared checkpoint awaiting
|
|
35
|
+
confirmation, or a stale confirmed artifact. A normalized answer alone does not require
|
|
36
|
+
a ceremonial checkpoint.
|
|
31
37
|
|
|
32
38
|
Every change-bound research, plan, dev, test, review, and deliver run inherits
|
|
33
39
|
the baseline id from the owning change workflow. A Prompt cannot switch that
|
|
@@ -37,11 +43,13 @@ it does not fabricate the missing provenance.
|
|
|
37
43
|
|
|
38
44
|
Ultra does not select product scope or material delivery posture; those remain user
|
|
39
45
|
decisions. Research references form an optional catalog, not a forced questionnaire.
|
|
40
|
-
The host model
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
The host model inspects evidence and recommends only relevant areas. The owner selects,
|
|
47
|
+
modifies, delegates, or defers that route through the native question surface unless
|
|
48
|
+
current intent already resolves it. The host records the normalized accepted coverage
|
|
49
|
+
and rationale. MCP validates identifiers, dispositions, evidence requirements,
|
|
50
|
+
synthesis, and at least one applicable semantic area; it does not prove the preceding
|
|
51
|
+
interaction. Omitted areas create no workflow step. An explicit `not_applicable` or
|
|
52
|
+
accepted `deferred` row is retained only when its exclusion is material.
|
|
45
53
|
|
|
46
54
|
## 2. How `ultra-init` classifies a repository
|
|
47
55
|
|
|
@@ -68,7 +76,7 @@ signals. In a monorepo, the owner selects the repository scope; baseline
|
|
|
68
76
|
worktree digests and accepted dirty files are restricted to that scope.
|
|
69
77
|
|
|
70
78
|
Classification and readiness are separate. Initialization immediately creates
|
|
71
|
-
or resumes `.ultra/state.db`, installs only the required scaffold, records the
|
|
79
|
+
or resumes `.ultra/.runtime/state.db`, installs only the required scaffold, records the
|
|
72
80
|
classification, and completes an `init` workflow after read-back verification. It
|
|
73
81
|
does not create a research run. A later explicit `ultra-research` invocation selects
|
|
74
82
|
`full` for greenfield or `adoption` for brownfield, records coverage dispositions, and
|
|
@@ -141,11 +149,12 @@ traceability, slice kind, public seam, exact verification command, acceptance
|
|
|
141
149
|
checks, context references, resolved documentation impact, owner, and valid
|
|
142
150
|
dependencies.
|
|
143
151
|
|
|
144
|
-
A semantic Change update
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
`
|
|
148
|
-
|
|
152
|
+
A semantic Change update traverses registered provenance and consumer edges and marks
|
|
153
|
+
only reachable task, workflow, and artifact consumers stale. Unrelated tasks remain
|
|
154
|
+
current. Clearing a task marker requires one complete execution-contract rebind through
|
|
155
|
+
`task.update`; a marker-only clear is rejected. MCP validates the resulting contract
|
|
156
|
+
and appends `task_contract_reconciled` with the current Change authority digest before
|
|
157
|
+
a new plan may converge.
|
|
149
158
|
|
|
150
159
|
A session process and a task have different status machines. Process exit zero closes
|
|
151
160
|
the execution transport but leaves the task `in_progress` until development,
|
|
@@ -195,33 +204,37 @@ making it `completed`.
|
|
|
195
204
|
### Decision thread and item
|
|
196
205
|
|
|
197
206
|
```text
|
|
198
|
-
thread: active ->
|
|
199
|
-
|
|
200
|
-
|
|
207
|
+
thread: active -> completed
|
|
208
|
+
|
|
|
209
|
+
+----> checkpoint_ready -> confirmed
|
|
210
|
+
^ | |
|
|
211
|
+
|--------------+--------------+ revision/supersession
|
|
201
212
|
|
|
202
213
|
item: open -> answered | delegated | deferred | superseded
|
|
203
214
|
```
|
|
204
215
|
|
|
205
216
|
A thread is bound to baseline, change, or workflow authority. A partial unique index
|
|
206
217
|
allows only one `open` item per thread. Resolved items remain immutable history;
|
|
207
|
-
changed evidence or intent uses `decision.supersede` and reopens
|
|
208
|
-
`decision.
|
|
209
|
-
|
|
210
|
-
|
|
218
|
+
changed evidence or intent uses `decision.supersede` and reopens alignment.
|
|
219
|
+
`decision.complete` closes settled normalized state without adding an approval claim.
|
|
220
|
+
When an artifact-bound recovery boundary is actually needed, `decision.checkpoint`
|
|
221
|
+
instead freezes a normalized decision digest and binds explicit owner approval to
|
|
222
|
+
current artifact digests or a justified standalone no-artifact case. Neither path
|
|
223
|
+
stores the conversation transcript.
|
|
211
224
|
|
|
212
225
|
## 4. Write and verification lifecycle
|
|
213
226
|
|
|
214
227
|
| Stage | Authoritative writes | Completion verification | Available continuation |
|
|
215
228
|
|---|---|---|---|
|
|
216
229
|
| `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` |
|
|
217
|
-
| `research` |
|
|
230
|
+
| `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 |
|
|
218
231
|
| 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 |
|
|
219
|
-
| `change` | Complete Change Contract, profile/risk rationale, research disposition,
|
|
220
|
-
| `plan` |
|
|
232
|
+
| `change` | Complete Change Contract, profile/risk rationale, research disposition, isolated Change root, typed delta, and a completed capture run; a decision thread only when material intent remains unresolved | Intent, acceptance, recovery, classification, research disposition, and exact baseline anchors are current | Model recommends; owner selects bounded `research` or direct `plan`; both routes converge on plan before development |
|
|
233
|
+
| `plan` | Accepted planning posture, immutable `plan/planning` context, selected planning evidence, complete change-owned task rows, acceptance coverage matrix, and deterministic `<artifact_root>/plan.json` plus `plan.md`; 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, and exported digests match current authority | Any dependency-ready task may enter `dev` |
|
|
221
234
|
| `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` |
|
|
222
|
-
| `test` | Immutable checking context, an explicit risk-selected verification profile, and
|
|
223
|
-
| `review` | Immutable review context
|
|
224
|
-
| `deliver` | Convergence context,
|
|
235
|
+
| `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` |
|
|
236
|
+
| `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 |
|
|
237
|
+
| `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 |
|
|
225
238
|
| `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 |
|
|
226
239
|
| `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 |
|
|
227
240
|
|
|
@@ -249,15 +262,31 @@ thread only for a new material decision cluster. Before asking, it must:
|
|
|
249
262
|
6. normalize the owner response with `decision.resolve`, explicit reversible
|
|
250
263
|
delegation with `decision.delegate`, or a consequence-bearing deferral with
|
|
251
264
|
`decision.defer`;
|
|
252
|
-
7.
|
|
253
|
-
|
|
265
|
+
7. apply accepted intent through the owning MCP operation or digest-bound artifact;
|
|
266
|
+
8. read the resulting authority back and record typed `applied_refs` when another
|
|
267
|
+
authority changed;
|
|
268
|
+
9. call `decision.complete` when normalized state is settled, or prepare a compact
|
|
269
|
+
checkpoint only when a material decision cluster changes a durable contract and
|
|
270
|
+
interruption recovery needs an artifact-bound boundary.
|
|
271
|
+
|
|
272
|
+
The shared semantic flow is `inspect -> suggest -> host-native ask -> normalize ->
|
|
273
|
+
persist -> apply -> read back`. The ask is skipped only when current explicit intent
|
|
274
|
+
already resolves the material choice. Claude Code and Kimi Code use `AskUserQuestion`, Codex uses
|
|
275
|
+
`request_user_input` when its current mode exposes it, and OpenCode uses `question`
|
|
276
|
+
when permitted. Every host falls back to one concise direct question when normal
|
|
277
|
+
conversation is still allowed. If the current host mode forbids interaction entirely,
|
|
278
|
+
the choice remains unanswered and route-dependent writes stop. A dismissed question
|
|
279
|
+
also remains unanswered. The DB trusts a normalized persisted result as current
|
|
280
|
+
authority across sessions; it does not store or verify a UI receipt, raw prompt, or
|
|
281
|
+
transcript. Breadcrumb and decision reads recall completed normalized intent, so a new
|
|
282
|
+
host session can continue without replaying the dialogue.
|
|
254
283
|
|
|
255
284
|
`ultra-think` owns this interaction protocol. `ultra-research`, `ultra-change`, and
|
|
256
285
|
`ultra-plan` invoke it at their decision boundaries. `ultra-dev`, `ultra-test`,
|
|
257
286
|
`ultra-review`, and `ultra-deliver` stop and route back to the same thread when new
|
|
258
287
|
owner authority is required; they never answer on the owner's behalf. `ultra-status`
|
|
259
|
-
shows
|
|
260
|
-
stale checkpoint artifacts and recovery state.
|
|
288
|
+
shows current unresolved decisions, relevant accepted intent, and the transition set,
|
|
289
|
+
while `ultra-doctor` diagnoses stale checkpoint artifacts and recovery state.
|
|
261
290
|
|
|
262
291
|
When only a bound artifact changes, the same resolved thread is prepared and approved
|
|
263
292
|
again against the current digest; this is checkpoint renewal, not a fabricated decision
|
|
@@ -271,37 +300,54 @@ opens one replacement.
|
|
|
271
300
|
- the bound baseline/change/task identity;
|
|
272
301
|
- a role and lifecycle gate;
|
|
273
302
|
- DB-backed task outcome, public seam, verification command, and required refs;
|
|
303
|
+
- the selected task's bounded dependency/integration neighborhood rather than every
|
|
304
|
+
unrelated task;
|
|
305
|
+
- the task-context contract: purpose, why, constraints, non-goals, target seams/files,
|
|
306
|
+
pattern refs, acceptance, documentation impact, recovery, and drift definition;
|
|
274
307
|
- local file hashes, current HEAD, branch, and worktree digest;
|
|
275
308
|
- optional metadata-only external memory or graph references;
|
|
276
|
-
- advisory file/token/context-share budgets;
|
|
309
|
+
- advisory file/token/context-share budgets, including inline Change/task authority;
|
|
277
310
|
- the current Change and task authority digests;
|
|
278
311
|
- readiness blockers, `allowed_transitions`, and a `required_transition` only for a
|
|
279
312
|
unique hard-recovery path.
|
|
280
313
|
|
|
314
|
+
Compilation is pure with respect to accepted Change authority. Provider references are
|
|
315
|
+
updated only through `change.update`; they cannot be smuggled into `change.context`.
|
|
316
|
+
Context references retain `expected_digest`, `anchor`, `scope`, and
|
|
317
|
+
`freshness_policy`. `digest` requires byte-current content, `existence` allows an
|
|
318
|
+
implementation target to change while remaining present, and `advisory` reports drift
|
|
319
|
+
without blocking.
|
|
320
|
+
|
|
281
321
|
Critical stage workflows bind a matching snapshot as a durable output:
|
|
282
322
|
|
|
283
323
|
| Workflow | Required role | Required gate |
|
|
284
324
|
|---|---|---|
|
|
325
|
+
| `plan` | `plan` | `planning` |
|
|
285
326
|
| `dev` | `implement` | `implementation` |
|
|
286
327
|
| `test` | `check` | `verification` |
|
|
287
328
|
| `review` | `review` | `review` |
|
|
288
329
|
| `deliver` | `check` | `convergence` |
|
|
289
330
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
current
|
|
331
|
+
Every lookup is exact on `change_id + task_id + role + gate`. The snapshot path and
|
|
332
|
+
digest are carried into plan, test, review, and delivery artifacts. `plan.export`
|
|
333
|
+
writes only the owning Change's `plan.json` and deterministic `plan.md`, and binds the
|
|
334
|
+
exact planning snapshot and digest to both the artifact registry and `verify-plan`.
|
|
335
|
+
The legacy global `.ultra/execution-plan.json` is read-only migration compatibility,
|
|
336
|
+
not current authority. These rules prevent a later Prompt or a different role packet
|
|
337
|
+
from claiming evidence gathered under another context. Referenced file content remains
|
|
338
|
+
lazy; only metadata and bounded task authority are inline. File and token budgets warn;
|
|
339
|
+
they do not block legitimate work. Missing authority, required refs, stale
|
|
340
|
+
digest-bound refs, task contracts, outputs, required owner decisions, or current gate
|
|
341
|
+
evidence do block.
|
|
296
342
|
|
|
297
343
|
## 7. Invalidation rules
|
|
298
344
|
|
|
299
345
|
- Changing a task contract invalidates contexts and gates that depended on the
|
|
300
346
|
former contract.
|
|
301
347
|
- Changing accepted Change intent, contract, classification, research disposition,
|
|
302
|
-
provider evidence, or documentation impact
|
|
303
|
-
|
|
304
|
-
|
|
348
|
+
provider evidence, or documentation impact invalidates only transitive registered
|
|
349
|
+
consumers. Planning or task reconciliation must explicitly refresh affected
|
|
350
|
+
authority before execution.
|
|
305
351
|
- Changing required source/spec content invalidates the recorded output or
|
|
306
352
|
context digest.
|
|
307
353
|
- Changing a research semantic source invalidates that workflow even when its immutable
|
|
@@ -315,10 +361,13 @@ current gate evidence do block.
|
|
|
315
361
|
overwrite historical evidence.
|
|
316
362
|
- `.ultra` workflow artifacts are excluded from application-worktree drift, but
|
|
317
363
|
their own recorded SHA-256 digests are still authoritative.
|
|
318
|
-
- Generated `tasks.json` and task-context
|
|
364
|
+
- Generated `tasks.json` and complete task-context files are projections. Manual edits
|
|
319
365
|
are overwritten and never repair DB authority.
|
|
320
366
|
- A changed checkpoint artifact digest or superseded decision invalidates the linked
|
|
321
367
|
decision checkpoint and blocks matching workflow advancement until reconfirmed.
|
|
368
|
+
- `workflow.revise` creates a candidate without deleting the completed prior run.
|
|
369
|
+
`workflow.supersede` promotes only a completed matching candidate, preserves both
|
|
370
|
+
histories, and invalidates only the prior run's transitive registered consumers.
|
|
322
371
|
|
|
323
372
|
## 8. Entry flows
|
|
324
373
|
|
|
@@ -326,9 +375,10 @@ current gate evidence do block.
|
|
|
326
375
|
|
|
327
376
|
```text
|
|
328
377
|
ultra-init -> Git/scaffold/authority verification -> init completed
|
|
329
|
-
-> explicit ultra-research ->
|
|
378
|
+
-> explicit ultra-research -> suggested route -> owner-selected accepted coverage
|
|
379
|
+
-> selected evidence work
|
|
330
380
|
-> local checkpoint when Git is unborn -> baseline approval
|
|
331
|
-
-> ultra-change -> optional bounded research
|
|
381
|
+
-> ultra-change -> optional bounded research -> typed delta -> plan -> dev -> risk-selected test/review
|
|
332
382
|
-> local deliver/archive
|
|
333
383
|
```
|
|
334
384
|
|
|
@@ -336,9 +386,9 @@ ultra-init -> Git/scaffold/authority verification -> init completed
|
|
|
336
386
|
|
|
337
387
|
```text
|
|
338
388
|
ultra-init -> preserve Git/classify brownfield -> init completed
|
|
339
|
-
-> explicit adoption research ->
|
|
389
|
+
-> explicit adoption research -> suggested route -> owner-selected accepted coverage
|
|
340
390
|
-> selected characterization/known-red evidence -> gap ledger -> owner approval
|
|
341
|
-
-> first ultra-change -> optional bounded research
|
|
391
|
+
-> first ultra-change -> optional bounded research -> typed delta -> plan -> dev -> test/review -> deliver
|
|
342
392
|
```
|
|
343
393
|
|
|
344
394
|
Adoption records the system that exists. It does not force the owner to recreate
|
|
@@ -358,8 +408,9 @@ Migration preserves prior files and rows but never carries old approval forward.
|
|
|
358
408
|
|
|
359
409
|
```text
|
|
360
410
|
ultra-status -> ultra-change intent capture
|
|
361
|
-
->
|
|
362
|
-
-> dev -> risk-selected test -> review
|
|
411
|
+
-> model recommends; owner selects bounded research or direct plan
|
|
412
|
+
-> typed delta -> plan -> dev -> risk-selected test -> review
|
|
413
|
+
-> documentation reconciliation -> atomic deliver -> reconciled baseline
|
|
363
414
|
```
|
|
364
415
|
|
|
365
416
|
Quick changes shorten the artifact burden only where the machine contract allows;
|
|
@@ -372,15 +423,15 @@ evidence rather than bypassing them.
|
|
|
372
423
|
| Entry | Owns | Normal handoff |
|
|
373
424
|
|---|---|---|
|
|
374
425
|
| `ultra-init` | classification, scope, Git/scaffold bootstrap, and init verification | stops completed; exposes research/status/doctor and any already-valid change capability |
|
|
375
|
-
| `ultra-research` | coverage disposition, selected evidence acquisition, synthesis, and material research decisions | baseline convergence or
|
|
426
|
+
| `ultra-research` | coverage disposition, selected evidence acquisition, synthesis, and material research decisions | baseline convergence or Change delta then plan |
|
|
376
427
|
| `ultra-think` | one material owner decision or read-only diagnosis | returns to the invoking capability after any needed checkpoint |
|
|
377
|
-
| `ultra-change` | outcome capture, Change Contract, risk/research routing |
|
|
428
|
+
| `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 |
|
|
378
429
|
| `ultra-plan` | task contracts, dependencies, acceptance coverage, optional material approval | any dependency-ready task through `ultra-dev` |
|
|
379
430
|
| `ultra-dev` | one task/session vertical slice and focused review | next `ultra-dev` task or aggregate `ultra-test` |
|
|
380
431
|
| `ultra-test` | risk-selected change acceptance and verification profile | `ultra-review` on pass, `ultra-dev`/`ultra-test` on failure |
|
|
381
432
|
| `ultra-review` | independent specification and engineering axes plus risk-selected workers | `ultra-deliver` on approval; otherwise implementation or checking |
|
|
382
433
|
| `ultra-deliver` | convergence, reconciliation, local archive, and delivery evidence | `ultra-status` or the next `ultra-change`; external release is separate |
|
|
383
|
-
| `ultra-status` | read-only authority and transition set |
|
|
434
|
+
| `ultra-status` | read-only authority and transition set | model recommendation; owner selection or delegation among allowed transitions |
|
|
384
435
|
| `ultra-doctor` | read-only diagnosis and authorized mechanical recovery | required recovery only when unique; otherwise safe alternatives |
|
|
385
436
|
|
|
386
437
|
Every row permits `ultra-think` when material owner authority is missing and permits
|
package/hooks/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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;
|
|
4
|
+
`.ultra/.runtime/state.db` and active continuous changes. Direct projection writes remain blocked;
|
|
5
5
|
context, compact, stop, and subagent lifecycle behavior is recovery-oriented and does not turn
|
|
6
6
|
advisory workflow conditions into refusal gates.
|
|
7
7
|
|
|
@@ -9,16 +9,17 @@ advisory workflow conditions into refusal gates.
|
|
|
9
9
|
|---|---|---|
|
|
10
10
|
| Session start | `health_check.py` | Read-only integrity, incident, projection, session, and change-artifact checks |
|
|
11
11
|
| 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
|
|
12
|
+
| Session start | `workflow_context.py` | Inject the DB-derived breadcrumb with bounded normalized accepted intent, never raw interaction or provider payloads |
|
|
13
13
|
| Before edit | `active_task_context.py` | Protect `tasks.json` and restate the same DB-derived task breadcrumb |
|
|
14
14
|
| Before compact | `workflow_checkpoint.py` | Validate and atomically save a minimal workflow checkpoint |
|
|
15
15
|
| After compact/resume | `workflow_resume.py` | Prefer the DB breadcrumb; restore the minimal file checkpoint only when no active change owns recovery |
|
|
16
16
|
| Stop | `pre_stop_check.py` | Report an incomplete workflow boundary and allow stop |
|
|
17
17
|
| Subagent lifecycle | `subagent_tracker.py` | Append minimal start/stop metadata to the authoritative DB event stream |
|
|
18
18
|
|
|
19
|
-
The plugin deliberately does not capture prompts, tool observations, transcripts, summaries,
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
The plugin deliberately does not capture prompts, tool observations, transcripts, summaries, general
|
|
20
|
+
conversational memory, or code-graph payloads. It does retain project-local Ultra workflow memory in
|
|
21
|
+
`.ultra/`. Generic command blocking and post-edit policy are user/repository governance. General
|
|
22
|
+
memory and graph content belongs to separately installed providers.
|
|
22
23
|
|
|
23
24
|
`subagent_tracker.py` passes only agent id/type and the host session id to the bundled
|
|
24
25
|
`hook-event.cjs` helper. The helper binds the current change/task and appends
|
|
@@ -5,26 +5,72 @@ import json
|
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
from context_spine import
|
|
8
|
+
from context_spine import (
|
|
9
|
+
ContextSpineError,
|
|
10
|
+
find_root,
|
|
11
|
+
read_breadcrumb,
|
|
12
|
+
render_breadcrumb,
|
|
13
|
+
)
|
|
9
14
|
|
|
10
15
|
TASKS_PROJECTION = Path(".ultra/tasks/tasks.json")
|
|
11
16
|
|
|
12
17
|
|
|
13
|
-
def
|
|
18
|
+
def tool_paths(data: dict, start: Path):
|
|
19
|
+
"""Yield absolute tool targets without assuming they belong to ``start``."""
|
|
14
20
|
tool_input = data.get("tool_input")
|
|
15
21
|
if not isinstance(tool_input, dict):
|
|
16
|
-
return
|
|
22
|
+
return
|
|
17
23
|
for key in ("file_path", "filePath", "filepath", "path"):
|
|
18
24
|
value = tool_input.get(key)
|
|
19
25
|
if not isinstance(value, str) or not value.strip():
|
|
20
26
|
continue
|
|
21
27
|
candidate = Path(value)
|
|
22
|
-
|
|
28
|
+
yield candidate.resolve() if candidate.is_absolute() else (start / candidate).resolve()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def projection_root_for_target(target: Path) -> Path | None:
|
|
32
|
+
"""Return the project root only for the exact generated tasks projection."""
|
|
33
|
+
if (
|
|
34
|
+
target.name == "tasks.json"
|
|
35
|
+
and target.parent.name == "tasks"
|
|
36
|
+
and target.parent.parent.name == ".ultra"
|
|
37
|
+
):
|
|
38
|
+
return target.parent.parent.parent
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def targets_tasks_projection(data: dict, root: Path) -> bool:
|
|
43
|
+
for resolved in tool_paths(data, root):
|
|
23
44
|
if resolved == (root / TASKS_PROJECTION).resolve():
|
|
24
45
|
return True
|
|
25
46
|
return False
|
|
26
47
|
|
|
27
48
|
|
|
49
|
+
def projection_denial(reason: str) -> dict:
|
|
50
|
+
return {"hookSpecificOutput": {
|
|
51
|
+
"hookEventName": "PreToolUse",
|
|
52
|
+
"permissionDecision": "deny",
|
|
53
|
+
"permissionDecisionReason": reason,
|
|
54
|
+
}}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def conflicted_projection_root(data: dict, start: Path) -> Path | None:
|
|
58
|
+
for candidate in (start, *start.parents):
|
|
59
|
+
if not (candidate / ".ultra").exists():
|
|
60
|
+
continue
|
|
61
|
+
if targets_tasks_projection(data, candidate):
|
|
62
|
+
return candidate
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def projection_roots(data: dict, start: Path):
|
|
67
|
+
"""Yield initialized project roots derived from every resolved tool target."""
|
|
68
|
+
for target in tool_paths(data, start):
|
|
69
|
+
root = projection_root_for_target(target)
|
|
70
|
+
if root is not None and (root / ".ultra").exists():
|
|
71
|
+
yield root
|
|
72
|
+
|
|
73
|
+
|
|
28
74
|
def main() -> None:
|
|
29
75
|
try:
|
|
30
76
|
data = json.loads(sys.stdin.read() or "{}")
|
|
@@ -32,20 +78,59 @@ def main() -> None:
|
|
|
32
78
|
except json.JSONDecodeError as exc:
|
|
33
79
|
print(f"[active_task_context] invalid hook input: {exc}", file=sys.stderr)
|
|
34
80
|
data = {}
|
|
35
|
-
|
|
81
|
+
start = Path(data.get("cwd") or Path.cwd()).resolve()
|
|
82
|
+
# An absolute tool target carries its own project boundary. Resolve and
|
|
83
|
+
# protect that authority before consulting cwd, because hooks may run from
|
|
84
|
+
# a host-owned temporary directory or another repository.
|
|
85
|
+
for target_root in projection_roots(data, start):
|
|
86
|
+
try:
|
|
87
|
+
target_authority = find_root(target_root)
|
|
88
|
+
except ContextSpineError as exc:
|
|
89
|
+
print(json.dumps(projection_denial(
|
|
90
|
+
"Refusing a direct write to an Ultra projection while the "
|
|
91
|
+
f"runtime authority is conflicted: {exc}. Resolve the "
|
|
92
|
+
"state.db conflict with ultra-doctor before editing generated "
|
|
93
|
+
"project artifacts."
|
|
94
|
+
)))
|
|
95
|
+
return
|
|
96
|
+
if target_authority is None:
|
|
97
|
+
continue
|
|
98
|
+
print(json.dumps(projection_denial(
|
|
99
|
+
"Refusing a direct write to the .ultra/tasks/tasks.json projection. "
|
|
100
|
+
".ultra/.runtime/state.db is authoritative; use the Ultra MCP task tools and "
|
|
101
|
+
"run ultra-doctor when state or projection health is degraded."
|
|
102
|
+
)))
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
root = find_root(start)
|
|
107
|
+
except ContextSpineError as exc:
|
|
108
|
+
print(
|
|
109
|
+
f"[active_task_context] cannot resolve Ultra root: {exc}",
|
|
110
|
+
file=sys.stderr,
|
|
111
|
+
)
|
|
112
|
+
# Ordinary context injection remains fail-open. A direct write to a
|
|
113
|
+
# known generated projection is different: an authority conflict
|
|
114
|
+
# means the hook cannot prove which DB would regenerate that file, so
|
|
115
|
+
# allowing the write would destroy the projection boundary.
|
|
116
|
+
if conflicted_projection_root(data, start) is not None:
|
|
117
|
+
print(json.dumps(projection_denial(
|
|
118
|
+
"Refusing a direct write to an Ultra projection while the "
|
|
119
|
+
f"runtime authority is conflicted: {exc}. Resolve the "
|
|
120
|
+
"state.db conflict with ultra-doctor before editing generated "
|
|
121
|
+
"project artifacts."
|
|
122
|
+
)))
|
|
123
|
+
return
|
|
124
|
+
root = None
|
|
36
125
|
if root is None:
|
|
37
126
|
print(json.dumps({}))
|
|
38
127
|
return
|
|
39
128
|
if targets_tasks_projection(data, root):
|
|
40
|
-
print(json.dumps(
|
|
41
|
-
"hookEventName": "PreToolUse",
|
|
42
|
-
"permissionDecision": "deny",
|
|
43
|
-
"permissionDecisionReason": (
|
|
129
|
+
print(json.dumps(projection_denial(
|
|
44
130
|
"Refusing a direct write to the .ultra/tasks/tasks.json projection. "
|
|
45
|
-
".ultra/state.db is authoritative; use the Ultra MCP task tools and "
|
|
131
|
+
".ultra/.runtime/state.db is authoritative; use the Ultra MCP task tools and "
|
|
46
132
|
"run ultra-doctor when state or projection health is degraded."
|
|
47
|
-
|
|
48
|
-
}}))
|
|
133
|
+
)))
|
|
49
134
|
return
|
|
50
135
|
try:
|
|
51
136
|
breadcrumb = read_breadcrumb(root)
|
package/hooks/context_spine.py
CHANGED
|
@@ -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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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:
|
package/hooks/health_check.py
CHANGED
|
@@ -6,7 +6,8 @@ import sqlite3
|
|
|
6
6
|
import sys
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from context_spine import ContextSpineError,
|
|
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
|
|
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 =
|
|
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
|
|
191
|
+
if not has_active_workflow(state_db_path(root)):
|
|
191
192
|
print(json.dumps({}))
|
|
192
193
|
return
|
|
193
194
|
report = inspect(root)
|
package/hooks/pre_stop_check.py
CHANGED
|
@@ -5,7 +5,7 @@ import json
|
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
from context_spine import ContextSpineError,
|
|
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 =
|
|
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
|