ultra-builder-pro-cli 0.21.1 → 0.23.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.
- package/.ultra-template/tasks/tasks.json +10 -3
- package/.ultra-template/templates/task-context.md +19 -0
- package/CHANGELOG.md +78 -0
- package/README.md +210 -36
- package/adapters/_shared/codex-assets.cjs +8 -3
- package/adapters/_shared/interaction-contract.cjs +13 -6
- package/adapters/_shared/runtime-assets.cjs +1 -1
- package/adapters/claude.js +1 -1
- package/adapters/kimi.js +1 -1
- package/adapters/opencode.js +24 -13
- package/docs/AGENT-CONTEXT.md +58 -51
- package/docs/ARCHITECTURE.md +82 -51
- package/docs/ARTIFACT-AUTHORITY.md +83 -44
- package/docs/COMMIT-HASH-BACKFILL.md +33 -90
- package/docs/DECISIONS.md +9 -7
- package/docs/LEGACY-CLI-CROSSWALK.md +10 -2
- package/docs/PLUGIN-ISOLATION-CONTRACT.md +3 -2
- package/docs/ROADMAP.md +3 -3
- package/docs/RUNTIME-COMPAT-MATRIX.md +13 -10
- package/docs/STATE-DB-ACCESS-POLICY.md +47 -19
- package/docs/WORKFLOW-LIFECYCLE.md +79 -49
- package/hooks/README.md +5 -4
- package/hooks/active_task_context.py +41 -39
- package/mcp-server/lib/artifact-registry.cjs +32 -7
- package/mcp-server/lib/baseline-workflow.cjs +60 -24
- package/mcp-server/lib/change-workflow.cjs +42 -6
- package/mcp-server/lib/context-paths.cjs +34 -3
- package/mcp-server/lib/doctor.cjs +28 -0
- package/mcp-server/lib/git-bootstrap.cjs +0 -1
- package/mcp-server/lib/init-project.cjs +52 -2
- package/mcp-server/lib/projector.cjs +43 -8
- package/mcp-server/lib/state-authority.cjs +19 -3
- package/mcp-server/lib/state-ops.cjs +6 -1
- package/mcp-server/lib/task-ledger.cjs +1342 -0
- package/mcp-server/lib/ultra-facade.cjs +646 -0
- package/mcp-server/lib/workflow-state.cjs +166 -2
- package/mcp-server/server.cjs +214 -26
- package/package.json +1 -1
- package/skills/ultra-change/SKILL.md +38 -90
- package/skills/ultra-deliver/SKILL.md +42 -62
- package/skills/ultra-dev/SKILL.md +34 -73
- package/skills/ultra-doctor/SKILL.md +26 -39
- package/skills/ultra-init/SKILL.md +37 -69
- package/skills/ultra-plan/SKILL.md +52 -125
- package/skills/ultra-research/SKILL.md +41 -101
- package/skills/ultra-review/SKILL.md +25 -44
- package/skills/ultra-status/SKILL.md +21 -40
- package/skills/ultra-test/SKILL.md +25 -60
- package/skills/ultra-think/SKILL.md +29 -48
- package/skills/ultra-think/references/decision-dialogue.md +6 -4
- package/spec/cli-protocol.md +15 -0
- package/spec/mcp-tools.yaml +286 -0
- package/spec/schemas/context-file.v4.5.schema.json +1 -1
- package/spec/schemas/mcp-tools.schema.json +1 -1
- package/spec/schemas/state-db.sql +1 -1
- package/spec/schemas/task-ledger.v1.schema.json +217 -0
- package/ultra-tools/commands/migrate.cjs +5 -2
- package/.ultra-template/tasks/contexts/TEMPLATE.md +0 -19
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
> Multi-process access contract. Current authority is defined by
|
|
4
4
|
> [`DECISIONS.md`](./DECISIONS.md) and the live database schema.
|
|
5
5
|
|
|
6
|
-
`.ultra/.runtime/state.db` is the
|
|
7
|
-
coordination authority for baselines, changes, decision threads/items, tasks,
|
|
6
|
+
`.ultra/.runtime/state.db` is the checkout-local lifecycle, index, transition,
|
|
7
|
+
freshness, and coordination authority for baselines, changes, decision threads/items, tasks,
|
|
8
8
|
workflow runs/steps, events, sessions, incidents, projections, telemetry, and spec
|
|
9
9
|
references (D18, D52, D54). Registered digest-bound files carry semantic and evidence
|
|
10
|
-
bodies; the DB owns their references and current digests.
|
|
11
|
-
|
|
10
|
+
bodies; the DB owns their references and current digests. The tracked
|
|
11
|
+
`.ultra/tasks/tasks.json` is an MCP-published handoff checkpoint, not a parallel live
|
|
12
|
+
writer. Every process that touches the DB must follow the rules below; deviations are
|
|
13
|
+
bugs.
|
|
12
14
|
|
|
13
15
|
## 1. Three-role write matrix
|
|
14
16
|
|
|
@@ -24,7 +26,7 @@ that touches it must follow the rules below; deviations are bugs.
|
|
|
24
26
|
but never `UPDATE` / `DELETE`.
|
|
25
27
|
|
|
26
28
|
The CLI may indirectly mutate ordinary workflow tables by spawning the MCP server over
|
|
27
|
-
stdio and calling
|
|
29
|
+
stdio and calling the public `ultra.*` kernel — but the actual
|
|
28
30
|
SQLite write is performed by the MCP server's writer connection. The documented
|
|
29
31
|
exceptions are initial schema/baseline creation, migration, and explicitly
|
|
30
32
|
authorized backup-first doctor recovery. The CLI never provides a parallel raw
|
|
@@ -34,8 +36,8 @@ The append-only carve-out for `events` exists because `events.id INTEGER
|
|
|
34
36
|
PRIMARY KEY AUTOINCREMENT` makes concurrent inserts collision-free under
|
|
35
37
|
WAL + `busy_timeout`. This lets hooks and short-lived CLI invocations
|
|
36
38
|
record audit observations without paying the cost of a full MCP round trip.
|
|
37
|
-
It does not grant lifecycle authority: external writers
|
|
38
|
-
|
|
39
|
+
It does not grant lifecycle authority: external writers use the published observation
|
|
40
|
+
allowlist, while lifecycle event
|
|
39
41
|
names are emitted only inside the mutation that owns the corresponding state change.
|
|
40
42
|
Consumers must verify mutable rows rather than infer success from an event name.
|
|
41
43
|
|
|
@@ -72,25 +74,48 @@ resolve the mount/runtime constraint before retrying.
|
|
|
72
74
|
|
|
73
75
|
| Table | Writer of record |
|
|
74
76
|
|--------------------|--------------------------------------------------------|
|
|
75
|
-
| `baselines` | MCP server
|
|
76
|
-
| `tasks` | MCP server
|
|
77
|
-
| `changes` | MCP server
|
|
78
|
-
| `decision_threads`, `decision_items` | MCP server
|
|
79
|
-
| `workflow_runs`, `workflow_steps` | MCP server
|
|
80
|
-
| `artifacts`, `artifact_edges` | MCP server
|
|
81
|
-
| `context_snapshots`, `spec_learning_candidates`, `trace_links` | MCP server through
|
|
77
|
+
| `baselines` | MCP server through `ultra.record`, `ultra.checkpoint`, and `ultra.archive`; initialization and legacy migration may create only the first draft or compatibility row |
|
|
78
|
+
| `tasks` | MCP server through `ultra.record`, `ultra.checkpoint`, and `ultra.sync` |
|
|
79
|
+
| `changes` | MCP server through `ultra.record`, `ultra.checkpoint`, and `ultra.archive` |
|
|
80
|
+
| `decision_threads`, `decision_items` | MCP server through `ultra.record`; normalized accepted intent and applied references are stored, never UI receipts, prompts, or transcripts |
|
|
81
|
+
| `workflow_runs`, `workflow_steps` | MCP server internally through `ultra.checkpoint`; Skills supply semantic evidence but never drive individual rows |
|
|
82
|
+
| `artifacts`, `artifact_edges` | MCP server through `ultra.record` and checkpoint-owned registration |
|
|
83
|
+
| `context_snapshots`, `spec_learning_candidates`, `trace_links` | MCP server through `ultra.record` and `ultra.checkpoint` |
|
|
82
84
|
| `incidents`, `projection_jobs`, `event_consumers`, `circuit_breaker` | MCP server; backup-first doctor recovery may perform only documented mechanical transitions |
|
|
83
|
-
| `events` | MCP server for lifecycle events; approved processes and `
|
|
84
|
-
| `sessions` | MCP server
|
|
85
|
+
| `events` | MCP server for lifecycle events; approved processes and `ultra.record` for allowlisted append-only observations |
|
|
86
|
+
| `sessions` | MCP server through `ultra.session`; orchestrator may write status transitions |
|
|
85
87
|
| `telemetry` | MCP server (collected from tool-call wrappers); orchestrator may dump bulk samples |
|
|
86
88
|
| `specs_refs` | MCP server (rebuilt on `spec_changed` event); orchestrator may rebuild |
|
|
87
89
|
| `migration_history`| schema initializer and `ultra-tools migrate` or doctor repair |
|
|
88
90
|
| `schema_version` | schema initializer, `ultra-tools db init`, migration, and doctor repair |
|
|
89
91
|
|
|
90
|
-
## 5.
|
|
92
|
+
## 5. Git team checkpoint
|
|
93
|
+
|
|
94
|
+
Only `ultra.sync { action: publish }` may derive `.ultra/tasks/tasks.json` from SQLite,
|
|
95
|
+
and only `ultra.sync { action: import }` may merge it into SQLite. Server startup performs one import after
|
|
96
|
+
opening project authority; later pulls in a long-running process require an explicit
|
|
97
|
+
import. The same checkpoint is idempotent and must not append an event again.
|
|
98
|
+
|
|
99
|
+
The checkpoint carries portable baseline, Change, and durable task records with
|
|
100
|
+
per-record revisions and digests. It excludes local `in_progress` ownership, sessions,
|
|
101
|
+
leases, worktrees, telemetry, and completion commit hashes. Import validates document
|
|
102
|
+
ancestry plus record-level common bases. It fast-forwards clean records and fails
|
|
103
|
+
before commit on same-record concurrency, parent/owner gaps, non-descendant history, or
|
|
104
|
+
an active-task collision. A Git-ready baseline is downgraded to checkout-local
|
|
105
|
+
revalidation rather than trusted as execution authority.
|
|
106
|
+
|
|
107
|
+
Legacy v4.4/v4.5 task projections are backed up and replaced only when every available
|
|
108
|
+
durable field matches current SQLite. Doctor reports checkpoint condition but never
|
|
109
|
+
performs semantic import, publication, or conflict selection.
|
|
110
|
+
|
|
111
|
+
## 6. Forbidden patterns
|
|
91
112
|
|
|
92
113
|
- **No file copies for state.** Don't `cp .ultra/.runtime/state.db
|
|
93
114
|
somewhere/state.db` and edit; use `ultra-tools db backup`.
|
|
115
|
+
- **No direct checkpoint edits.** Don't merge or repair
|
|
116
|
+
`.ultra/tasks/tasks.json` by hand; use the typed import/publish conflict path.
|
|
117
|
+
- **No committed live projections.** `.ultra/.runtime/projections/**` remains ignored
|
|
118
|
+
checkout-local output.
|
|
94
119
|
- **No long-held writer connections** outside the MCP server. Pop a
|
|
95
120
|
short transaction, finish, close.
|
|
96
121
|
- **No `PRAGMA journal_mode` toggling at runtime** by any process other
|
|
@@ -100,14 +125,14 @@ resolve the mount/runtime constraint before retrying.
|
|
|
100
125
|
- **No `vacuum` / `wal_checkpoint(TRUNCATE)` from inside a transaction.**
|
|
101
126
|
Maintenance subcommands open their own connection.
|
|
102
127
|
|
|
103
|
-
##
|
|
128
|
+
## 7. Maintenance windows
|
|
104
129
|
|
|
105
130
|
`ultra-tools db checkpoint` and `ultra-tools db vacuum` are safe to run
|
|
106
131
|
while the MCP server is up (they take their own connection and obey the
|
|
107
132
|
busy timeout). `db backup` uses better-sqlite3's online `.backup` API
|
|
108
133
|
and produces a consistent snapshot without blocking writers.
|
|
109
134
|
|
|
110
|
-
##
|
|
135
|
+
## 8. Verification
|
|
111
136
|
|
|
112
137
|
The contract on this page is enforced by:
|
|
113
138
|
|
|
@@ -119,3 +144,6 @@ The contract on this page is enforced by:
|
|
|
119
144
|
status transitions, task contracts, and event coupling.
|
|
120
145
|
- `mcp-server/lib/workflow-state.test.cjs` — ordered workflow transitions,
|
|
121
146
|
evidence/output requirements, blocking/resume, and cross-stage gates.
|
|
147
|
+
- `mcp-server/lib/task-ledger.test.cjs` — portable-field filtering, digest ancestry,
|
|
148
|
+
idempotent import, baseline/Change/task fast-forward and conflict behavior, legacy
|
|
149
|
+
backup, and active-session protection.
|
|
@@ -11,29 +11,33 @@ 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 |
|
|
15
|
-
| `.ultra/.runtime/state.db` |
|
|
14
|
+
| MCP | Durable checkpoints, task contracts, evidence references, output hashes, team sync, leases, archives, and mechanical recovery | 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 |
|
|
16
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 |
|
|
17
|
-
| Generated projections and scratch |
|
|
18
|
-
| Hook | Compact DB-derived lifecycle observation, minimal event metadata, and projection
|
|
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 |
|
|
19
20
|
|
|
20
21
|
Together, `.ultra/` is project-local cross-session workflow memory. The detailed
|
|
21
22
|
artifact classes and promotion rules live in
|
|
22
23
|
[`ARTIFACT-AUTHORITY.md`](./ARTIFACT-AUTHORITY.md).
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
as MCP authority.
|
|
25
|
+
Model input can supply facts, content paths, reasons, owner decisions, and evidence
|
|
26
|
+
references. `ultra.record` stores mutable typed drafts and `ultra.checkpoint` attempts
|
|
27
|
+
one durable semantic commit. A semantic rejection returns diagnostics and keeps the
|
|
28
|
+
draft editable. Model input cannot override a task's public seam, evidence digest, or
|
|
29
|
+
accepted checkpoint. A host recommendation is never stored as MCP authority.
|
|
30
30
|
|
|
31
|
-
Load-bearing owner choices are normalized through `
|
|
32
|
-
durable authority. The host acquires observable facts autonomously, exposes one
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
Load-bearing owner choices are normalized through `ultra.record`; prompt prose is not
|
|
32
|
+
durable authority. The host acquires observable facts autonomously, exposes one current
|
|
33
|
+
question, and stops. Unanswered material choices remain warnings or checkpoint
|
|
34
|
+
diagnostics until a capability truly needs their result. A normalized answer alone
|
|
35
|
+
does not require a ceremonial checkpoint.
|
|
36
|
+
|
|
37
|
+
Every host discovers seven public MCP tools: `ultra.context`, `ultra.record`,
|
|
38
|
+
`ultra.checkpoint`, `ultra.sync`, `ultra.session`, `ultra.archive`, and
|
|
39
|
+
`ultra.doctor`. The 0.22 fine-grained operations documented below remain hidden
|
|
40
|
+
compatibility internals for one release. Skills must not drive them one call at a time.
|
|
37
41
|
|
|
38
42
|
Every change-bound research, plan, dev, test, review, and deliver run inherits
|
|
39
43
|
the baseline id from the owning change workflow. A Prompt cannot switch that
|
|
@@ -76,8 +80,10 @@ signals. In a monorepo, the owner selects the repository scope; baseline
|
|
|
76
80
|
worktree digests and accepted dirty files are restricted to that scope.
|
|
77
81
|
|
|
78
82
|
Classification and readiness are separate. Initialization immediately creates
|
|
79
|
-
or resumes `.ultra/.runtime/state.db`,
|
|
80
|
-
|
|
83
|
+
or resumes `.ultra/.runtime/state.db`, creates or imports the Git team checkpoint,
|
|
84
|
+
installs only the required scaffold, records the classification, and completes an
|
|
85
|
+
`init` workflow after read-back verification. A ready checkpoint baseline is held for
|
|
86
|
+
checkout-local revalidation. Init
|
|
81
87
|
does not create a research run. A later explicit `ultra-research` invocation selects
|
|
82
88
|
`full` for greenfield or `adoption` for brownfield, records coverage dispositions, and
|
|
83
89
|
works toward baseline readiness. Empty templates are not an approved baseline.
|
|
@@ -187,8 +193,10 @@ execution failure.
|
|
|
187
193
|
### Workflow run and step
|
|
188
194
|
|
|
189
195
|
```text
|
|
190
|
-
|
|
191
|
-
|
|
196
|
+
draft: active <-> blocked <-> ready
|
|
197
|
+
| | |
|
|
198
|
+
+----------+---------+----> cancelled
|
|
199
|
+
\----> completed (accepted, immutable)
|
|
192
200
|
|
|
193
201
|
step: pending -> in_progress -> completed
|
|
194
202
|
| |
|
|
@@ -196,10 +204,10 @@ step: pending -> in_progress -> completed
|
|
|
196
204
|
blocked ------> in_progress/completed
|
|
197
205
|
```
|
|
198
206
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
207
|
+
Fine-grained steps are internal evidence bookkeeping. `ultra.checkpoint` records and
|
|
208
|
+
validates them in one public call. A missing output returns mutable diagnostics. Draft
|
|
209
|
+
artifact changes reopen `ready` to `active`; only an accepted `completed` revision is
|
|
210
|
+
immutable.
|
|
203
211
|
|
|
204
212
|
### Decision thread and item
|
|
205
213
|
|
|
@@ -226,24 +234,41 @@ stores the conversation transcript.
|
|
|
226
234
|
|
|
227
235
|
| Stage | Authoritative writes | Completion verification | Available continuation |
|
|
228
236
|
|---|---|---|---|
|
|
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` |
|
|
237
|
+
| `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` |
|
|
230
238
|
| `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 |
|
|
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 |
|
|
232
|
-
| `change` | Complete Change Contract, profile/risk rationale, research disposition, isolated Change root, typed delta,
|
|
233
|
-
| `plan` | Accepted planning posture, immutable `plan/planning` context, selected planning evidence, complete change-owned task rows, acceptance coverage matrix,
|
|
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
|
|
239
|
+
| 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 |
|
|
240
|
+
| `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 |
|
|
241
|
+
| `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` |
|
|
242
|
+
| `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` |
|
|
235
243
|
| `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
244
|
| `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
245
|
| `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 |
|
|
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 |
|
|
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 |
|
|
246
|
+
| `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 |
|
|
247
|
+
| `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 |
|
|
240
248
|
|
|
241
|
-
Every mutating MCP operation appends an event and enqueues projection work when
|
|
242
|
-
the corresponding read-only view can change. Projection failure is recorded as
|
|
249
|
+
Every mutating MCP operation appends an event and enqueues local projection work when
|
|
250
|
+
the corresponding checkout-local read-only view can change. Projection failure is recorded as
|
|
243
251
|
a retryable incident; it does not silently convert a failed write into success.
|
|
252
|
+
Semantic handoff operations separately publish the Git team checkpoint.
|
|
244
253
|
`task.append_event` accepts only non-authoritative observations. Lifecycle events are
|
|
245
254
|
emitted by their owning DB mutation and never act as a substitute state transition.
|
|
246
255
|
|
|
256
|
+
### Team handoff checkpoint
|
|
257
|
+
|
|
258
|
+
The Git checkpoint is intentionally lower-frequency than SQLite. It publishes accepted
|
|
259
|
+
baseline, Change, plan, task-contract, and durable task-status boundaries; it does not
|
|
260
|
+
mirror heartbeats, leases, active processes, telemetry, or provisional completion
|
|
261
|
+
hashes. On MCP startup or explicit post-pull import, the receiving checkout validates
|
|
262
|
+
checkpoint ancestry and record digests. Clean baseline, Change, and task records
|
|
263
|
+
fast-forward independently. Concurrent edits to the same record or a remote edit to a
|
|
264
|
+
locally active task stop without partial import.
|
|
265
|
+
|
|
266
|
+
A checkpoint can restore portable project intent after clone, but cannot establish
|
|
267
|
+
checkout truth by itself. An imported ready baseline becomes a local adoption/draft
|
|
268
|
+
with `team-ledger-revalidation-required`; current scope content, HEAD, verification,
|
|
269
|
+
known failures, and approval must converge again. Because baseline content hashing
|
|
270
|
+
excludes `.ultra/`, committing the checkpoint cannot make its own baseline stale.
|
|
271
|
+
|
|
247
272
|
## 5. Human-agent alignment lifecycle
|
|
248
273
|
|
|
249
274
|
The host first reads `decision.list` and resumes matching authority. It starts a new
|
|
@@ -295,7 +320,8 @@ opens one replacement.
|
|
|
295
320
|
|
|
296
321
|
## 6. Context and prompt follow-through
|
|
297
322
|
|
|
298
|
-
|
|
323
|
+
The Context compiler used internally by `ultra.checkpoint` creates an immutable
|
|
324
|
+
Context Manifest v3 snapshot. It combines:
|
|
299
325
|
|
|
300
326
|
- the bound baseline/change/task identity;
|
|
301
327
|
- a role and lifecycle gate;
|
|
@@ -308,11 +334,10 @@ opens one replacement.
|
|
|
308
334
|
- optional metadata-only external memory or graph references;
|
|
309
335
|
- advisory file/token/context-share budgets, including inline Change/task authority;
|
|
310
336
|
- the current Change and task authority digests;
|
|
311
|
-
- readiness
|
|
312
|
-
unique hard-recovery path.
|
|
337
|
+
- readiness warnings and hard mechanical blockers without a semantic route command.
|
|
313
338
|
|
|
314
339
|
Compilation is pure with respect to accepted Change authority. Provider references are
|
|
315
|
-
|
|
340
|
+
recorded through `ultra.record`; they cannot be smuggled into a checkpoint context.
|
|
316
341
|
Context references retain `expected_digest`, `anchor`, `scope`, and
|
|
317
342
|
`freshness_policy`. `digest` requires byte-current content, `existence` allows an
|
|
318
343
|
implementation target to change while remaining present, and `advisory` reports drift
|
|
@@ -329,9 +354,9 @@ Critical stage workflows bind a matching snapshot as a durable output:
|
|
|
329
354
|
| `deliver` | `check` | `convergence` |
|
|
330
355
|
|
|
331
356
|
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.
|
|
333
|
-
writes
|
|
334
|
-
exact planning snapshot and digest to
|
|
357
|
+
digest are carried into plan, test, review, and delivery artifacts. The Plan
|
|
358
|
+
`ultra.checkpoint` writes the owning Change's `plan.json` and deterministic `plan.md`
|
|
359
|
+
once, and binds the exact planning snapshot and digest to the artifact registry.
|
|
335
360
|
The legacy global `.ultra/execution-plan.json` is read-only migration compatibility,
|
|
336
361
|
not current authority. These rules prevent a later Prompt or a different role packet
|
|
337
362
|
from claiming evidence gathered under another context. Referenced file content remains
|
|
@@ -361,13 +386,17 @@ evidence do block.
|
|
|
361
386
|
overwrite historical evidence.
|
|
362
387
|
- `.ultra` workflow artifacts are excluded from application-worktree drift, but
|
|
363
388
|
their own recorded SHA-256 digests are still authoritative.
|
|
364
|
-
- Generated
|
|
365
|
-
are overwritten and never repair DB
|
|
389
|
+
- Generated `.ultra/.runtime/projections/tasks.json` and complete runtime task-context
|
|
390
|
+
files are local projections. Manual edits are overwritten and never repair DB
|
|
391
|
+
authority.
|
|
392
|
+
- `.ultra/tasks/tasks.json` is a tracked MCP checkpoint, not a local projection.
|
|
393
|
+
Its full and per-record digests reject manual edits; publish/import performs typed
|
|
394
|
+
fast-forward or conflict handling.
|
|
366
395
|
- A changed checkpoint artifact digest or superseded decision invalidates the linked
|
|
367
396
|
decision checkpoint and blocks matching workflow advancement until reconfirmed.
|
|
368
|
-
-
|
|
369
|
-
|
|
370
|
-
|
|
397
|
+
- A rejected draft is repaired in place or explicitly abandoned. A new accepted
|
|
398
|
+
revision preserves prior accepted history and invalidates only true transitive
|
|
399
|
+
registered consumers.
|
|
371
400
|
|
|
372
401
|
## 8. Entry flows
|
|
373
402
|
|
|
@@ -435,13 +464,14 @@ evidence rather than bypassing them.
|
|
|
435
464
|
| `ultra-doctor` | read-only diagnosis and authorized mechanical recovery | required recovery only when unique; otherwise safe alternatives |
|
|
436
465
|
|
|
437
466
|
Every row permits `ultra-think` when material owner authority is missing and permits
|
|
438
|
-
`ultra-doctor` when state or installed-runtime authority is unhealthy.
|
|
439
|
-
|
|
440
|
-
|
|
467
|
+
`ultra-doctor` when state or installed-runtime authority is unhealthy. The host model
|
|
468
|
+
recommends either from current evidence; hard MCP blockers remain limited to the
|
|
469
|
+
mechanical safety boundary. Neither capability creates a parallel workflow or
|
|
470
|
+
substitutes a prompt summary for DB state.
|
|
441
471
|
|
|
442
472
|
## 9. Recovery and diagnosis
|
|
443
473
|
|
|
444
|
-
Use `
|
|
474
|
+
Use `ultra.doctor` for project authority and
|
|
445
475
|
`ubp --all --global --doctor` for installed host assets. Both are read-only
|
|
446
476
|
unless an explicit project repair command is chosen.
|
|
447
477
|
|
package/hooks/README.md
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
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/.runtime/state.db` and active continuous changes. Direct
|
|
5
|
-
context, compact, stop, and subagent
|
|
6
|
-
advisory workflow conditions into
|
|
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
13
|
| Session start | `workflow_context.py` | Inject the DB-derived breadcrumb with bounded normalized accepted intent, never raw interaction or provider payloads |
|
|
13
|
-
| Before edit | `active_task_context.py` | Protect
|
|
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 |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Protect Ultra
|
|
2
|
+
"""Protect Ultra managed task files and restate the active workflow boundary."""
|
|
3
3
|
|
|
4
4
|
import json
|
|
5
5
|
import sys
|
|
@@ -12,7 +12,9 @@ from context_spine import (
|
|
|
12
12
|
render_breadcrumb,
|
|
13
13
|
)
|
|
14
14
|
|
|
15
|
-
|
|
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)
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
def tool_paths(data: dict, start: Path):
|
|
@@ -28,25 +30,24 @@ def tool_paths(data: dict, start: Path):
|
|
|
28
30
|
yield candidate.resolve() if candidate.is_absolute() else (start / candidate).resolve()
|
|
29
31
|
|
|
30
32
|
|
|
31
|
-
def
|
|
32
|
-
"""Return the project root
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
and
|
|
37
|
-
|
|
38
|
-
return target.parent.parent.parent
|
|
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)])
|
|
39
40
|
return None
|
|
40
41
|
|
|
41
42
|
|
|
42
|
-
def
|
|
43
|
+
def targets_managed_task_file(data: dict, root: Path) -> bool:
|
|
43
44
|
for resolved in tool_paths(data, root):
|
|
44
|
-
if resolved == (root /
|
|
45
|
+
if any(resolved == (root / relative).resolve() for relative in PROTECTED_TASK_FILES):
|
|
45
46
|
return True
|
|
46
47
|
return False
|
|
47
48
|
|
|
48
49
|
|
|
49
|
-
def
|
|
50
|
+
def managed_file_denial(reason: str) -> dict:
|
|
50
51
|
return {"hookSpecificOutput": {
|
|
51
52
|
"hookEventName": "PreToolUse",
|
|
52
53
|
"permissionDecision": "deny",
|
|
@@ -54,19 +55,19 @@ def projection_denial(reason: str) -> dict:
|
|
|
54
55
|
}}
|
|
55
56
|
|
|
56
57
|
|
|
57
|
-
def
|
|
58
|
+
def conflicted_managed_root(data: dict, start: Path) -> Path | None:
|
|
58
59
|
for candidate in (start, *start.parents):
|
|
59
60
|
if not (candidate / ".ultra").exists():
|
|
60
61
|
continue
|
|
61
|
-
if
|
|
62
|
+
if targets_managed_task_file(data, candidate):
|
|
62
63
|
return candidate
|
|
63
64
|
return None
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
def
|
|
67
|
+
def managed_roots(data: dict, start: Path):
|
|
67
68
|
"""Yield initialized project roots derived from every resolved tool target."""
|
|
68
69
|
for target in tool_paths(data, start):
|
|
69
|
-
root =
|
|
70
|
+
root = protected_root_for_target(target)
|
|
70
71
|
if root is not None and (root / ".ultra").exists():
|
|
71
72
|
yield root
|
|
72
73
|
|
|
@@ -82,23 +83,24 @@ def main() -> None:
|
|
|
82
83
|
# An absolute tool target carries its own project boundary. Resolve and
|
|
83
84
|
# protect that authority before consulting cwd, because hooks may run from
|
|
84
85
|
# a host-owned temporary directory or another repository.
|
|
85
|
-
for target_root in
|
|
86
|
+
for target_root in managed_roots(data, start):
|
|
86
87
|
try:
|
|
87
88
|
target_authority = find_root(target_root)
|
|
88
89
|
except ContextSpineError as exc:
|
|
89
|
-
print(json.dumps(
|
|
90
|
-
"Refusing a direct write to an Ultra
|
|
90
|
+
print(json.dumps(managed_file_denial(
|
|
91
|
+
"Refusing a direct write to an MCP-managed Ultra task file while the "
|
|
91
92
|
f"runtime authority is conflicted: {exc}. Resolve the "
|
|
92
|
-
"state.db conflict with ultra-doctor before
|
|
93
|
-
"
|
|
93
|
+
"state.db conflict with ultra-doctor before retrying the owning "
|
|
94
|
+
"MCP operation."
|
|
94
95
|
)))
|
|
95
96
|
return
|
|
96
97
|
if target_authority is None:
|
|
97
98
|
continue
|
|
98
|
-
print(json.dumps(
|
|
99
|
-
"Refusing a direct write to
|
|
100
|
-
".ultra
|
|
101
|
-
"
|
|
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."
|
|
102
104
|
)))
|
|
103
105
|
return
|
|
104
106
|
|
|
@@ -110,26 +112,26 @@ def main() -> None:
|
|
|
110
112
|
file=sys.stderr,
|
|
111
113
|
)
|
|
112
114
|
# Ordinary context injection remains fail-open. A direct write to a
|
|
113
|
-
# known
|
|
114
|
-
#
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"Refusing a direct write to an Ultra projection while the "
|
|
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 "
|
|
119
120
|
f"runtime authority is conflicted: {exc}. Resolve the "
|
|
120
|
-
"state.db conflict with ultra-doctor before
|
|
121
|
-
"
|
|
121
|
+
"state.db conflict with ultra-doctor before retrying the owning "
|
|
122
|
+
"MCP operation."
|
|
122
123
|
)))
|
|
123
124
|
return
|
|
124
125
|
root = None
|
|
125
126
|
if root is None:
|
|
126
127
|
print(json.dumps({}))
|
|
127
128
|
return
|
|
128
|
-
if
|
|
129
|
-
print(json.dumps(
|
|
130
|
-
"Refusing a direct write to
|
|
131
|
-
".ultra
|
|
132
|
-
"
|
|
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."
|
|
133
135
|
)))
|
|
134
136
|
return
|
|
135
137
|
try:
|
|
@@ -27,7 +27,7 @@ const STATIC_EXEMPT_PATHS = new Set([
|
|
|
27
27
|
'.ultra/docs/research/README.md',
|
|
28
28
|
'.ultra/reports/templates/delivery-report.json',
|
|
29
29
|
'.ultra/reports/templates/test-report.json',
|
|
30
|
-
'.ultra/
|
|
30
|
+
'.ultra/templates/task-context.md',
|
|
31
31
|
'.ultra/tasks/tasks.json',
|
|
32
32
|
'.ultra/changes/active/.gitkeep',
|
|
33
33
|
'.ultra/changes/archive/.gitkeep',
|
|
@@ -81,9 +81,10 @@ function isExemptArtifactPath(value) {
|
|
|
81
81
|
|
|
82
82
|
function isGeneratedProjectionPath(value) {
|
|
83
83
|
const relative = normalizeRelativePath(value);
|
|
84
|
-
return relative === '.ultra/
|
|
85
|
-
|| relative.startsWith('.ultra/
|
|
86
|
-
|| relative === '.ultra/tasks/
|
|
84
|
+
return relative === '.ultra/.runtime/projections'
|
|
85
|
+
|| relative.startsWith('.ultra/.runtime/projections/')
|
|
86
|
+
|| relative === '.ultra/tasks/contexts'
|
|
87
|
+
|| relative.startsWith('.ultra/tasks/contexts/');
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
function artifactPathError(message, details = undefined) {
|
|
@@ -504,10 +505,34 @@ function invalidateConsumersFromEndpointInTx(db, start, {
|
|
|
504
505
|
}
|
|
505
506
|
if (endpoint.type === 'workflow') {
|
|
506
507
|
const row = db.prepare(
|
|
507
|
-
'SELECT metadata_json, change_id, task_id FROM workflow_runs WHERE id = ?',
|
|
508
|
+
'SELECT status, metadata_json, change_id, task_id FROM workflow_runs WHERE id = ?',
|
|
508
509
|
).get(endpoint.id);
|
|
509
510
|
if (row) {
|
|
510
511
|
const metadata = parseJson(row.metadata_json, {});
|
|
512
|
+
if (['active', 'blocked', 'ready'].includes(row.status)) {
|
|
513
|
+
delete metadata.authority_invalidation;
|
|
514
|
+
metadata.draft_dirty = true;
|
|
515
|
+
db.prepare(
|
|
516
|
+
`UPDATE workflow_runs
|
|
517
|
+
SET status = CASE WHEN status = 'ready' THEN 'active' ELSE status END,
|
|
518
|
+
metadata_json = ?,
|
|
519
|
+
updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
520
|
+
WHERE id = ?`,
|
|
521
|
+
).run(JSON.stringify(metadata), endpoint.id);
|
|
522
|
+
ops.appendEventInTx(db, {
|
|
523
|
+
type: 'workflow_draft_changed',
|
|
524
|
+
change_id: row.change_id,
|
|
525
|
+
task_id: row.task_id,
|
|
526
|
+
payload: {
|
|
527
|
+
workflow_id: endpoint.id,
|
|
528
|
+
source_type: start.type,
|
|
529
|
+
source_id: start.id,
|
|
530
|
+
reason,
|
|
531
|
+
},
|
|
532
|
+
});
|
|
533
|
+
queue.push(...outgoingEdges(db, endpoint));
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
511
536
|
if (metadata.authority_invalidation?.invalidated !== true) {
|
|
512
537
|
metadata.authority_invalidation = {
|
|
513
538
|
invalidated: true,
|
|
@@ -950,7 +975,7 @@ function knownArtifactPaths(db) {
|
|
|
950
975
|
}
|
|
951
976
|
for (const row of db.prepare('SELECT id, context_file FROM tasks').all()) {
|
|
952
977
|
known.add(normalizeRelativePath(
|
|
953
|
-
row.context_file
|
|
978
|
+
contextPaths.resolveContextPath('.', row.context_file, { taskId: row.id }).relative,
|
|
954
979
|
));
|
|
955
980
|
}
|
|
956
981
|
return known;
|
|
@@ -1078,7 +1103,7 @@ function inspectArtifactHealth(db, { rootDir = process.cwd() } = {}) {
|
|
|
1078
1103
|
for (const relative of tree.files) {
|
|
1079
1104
|
if (isExemptArtifactPath(relative) || known.has(relative)) continue;
|
|
1080
1105
|
if (!readyBaseline && PROVISIONAL_BASELINE_SPEC_PATHS.has(relative)) continue;
|
|
1081
|
-
if (relative.startsWith(`${contextPaths.
|
|
1106
|
+
if (relative.startsWith(`${contextPaths.LEGACY_CONTEXT_ROOT_RELATIVE}/`)) {
|
|
1082
1107
|
let contents;
|
|
1083
1108
|
try {
|
|
1084
1109
|
contents = readStableProjectFile(rootDir, relative).bytes;
|