ultra-builder-pro-cli 0.12.1 → 0.14.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 (88) hide show
  1. package/.ultra-template/docs/research/README.md +21 -44
  2. package/.ultra-template/specs/discovery.md +10 -0
  3. package/CHANGELOG.md +95 -1
  4. package/README.md +31 -16
  5. package/adapters/_shared/codex-assets.cjs +23 -163
  6. package/adapters/_shared/handbook.cjs +2 -2
  7. package/adapters/_shared/runtime-assets.cjs +1 -0
  8. package/adapters/_shared/tests/runtime-assets.test.cjs +18 -0
  9. package/adapters/opencode.js +30 -120
  10. package/adapters/tests/claude.test.cjs +3 -2
  11. package/adapters/tests/codex-hook.test.cjs +34 -7
  12. package/adapters/tests/codex.test.cjs +21 -6
  13. package/adapters/tests/kimi-hook.test.cjs +34 -7
  14. package/adapters/tests/opencode.test.cjs +70 -84
  15. package/commands/ultra-init.md +1 -1
  16. package/docs/AGENT-CONTEXT.md +10 -6
  17. package/docs/ARCHITECTURE.md +40 -17
  18. package/docs/PLAN.zh-CN.md +5 -4
  19. package/docs/ROADMAP.md +2 -2
  20. package/docs/RUNTIME-COMPAT-MATRIX.md +4 -4
  21. package/docs/STATE-DB-ACCESS-POLICY.md +3 -3
  22. package/docs/USER-HANDBOOK-CONTRACT.md +5 -4
  23. package/hooks/active_task_context.py +22 -50
  24. package/hooks/context_spine.py +61 -299
  25. package/hooks/health_check.py +19 -17
  26. package/hooks/pre_stop_check.py +28 -33
  27. package/hooks/subagent_tracker.py +13 -19
  28. package/hooks/workflow_checkpoint.py +39 -47
  29. package/hooks/workflow_context.py +4 -9
  30. package/hooks/workflow_resume.py +48 -128
  31. package/mcp-server/breadcrumb.cjs +22 -0
  32. package/mcp-server/lib/archive-journal.cjs +192 -0
  33. package/mcp-server/lib/archive-journal.test.cjs +35 -0
  34. package/mcp-server/lib/baseline-workflow.cjs +404 -38
  35. package/mcp-server/lib/baseline-workflow.test.cjs +252 -0
  36. package/mcp-server/lib/change-workflow.cjs +249 -75
  37. package/mcp-server/lib/change-workflow.test.cjs +235 -1
  38. package/mcp-server/lib/context-spine.test.cjs +5 -0
  39. package/mcp-server/lib/doctor.cjs +14 -1
  40. package/mcp-server/lib/doctor.test.cjs +42 -4
  41. package/mcp-server/lib/init-project.cjs +292 -9
  42. package/mcp-server/lib/prd-parser.cjs +14 -41
  43. package/mcp-server/lib/prd-parser.test.cjs +49 -138
  44. package/mcp-server/lib/project-breadcrumb.cjs +139 -0
  45. package/mcp-server/lib/project-breadcrumb.test.cjs +112 -0
  46. package/mcp-server/lib/spec-learning.test.cjs +1 -1
  47. package/mcp-server/lib/state-authority.cjs +9 -3
  48. package/mcp-server/lib/state-db.cjs +154 -32
  49. package/mcp-server/lib/state-db.test.cjs +136 -4
  50. package/mcp-server/lib/state-ops.cjs +68 -6
  51. package/mcp-server/lib/task-expander.cjs +14 -37
  52. package/mcp-server/lib/task-expander.test.cjs +80 -164
  53. package/mcp-server/server.cjs +34 -37
  54. package/mcp-server/tests/init-project.test.cjs +162 -1
  55. package/mcp-server/tests/migrate.test.cjs +33 -0
  56. package/mcp-server/tests/server-contract.test.cjs +391 -17
  57. package/mcp-server/tests/state-db.test.cjs +14 -2
  58. package/mcp-server/tests/state-ops.test.cjs +108 -0
  59. package/package.json +2 -4
  60. package/skills/cc-collab/SKILL.md +2 -2
  61. package/skills/codex-collab/SKILL.md +2 -3
  62. package/skills/ultra-change/SKILL.md +18 -10
  63. package/skills/ultra-deliver/SKILL.md +13 -9
  64. package/skills/ultra-dev/SKILL.md +6 -4
  65. package/skills/ultra-doctor/SKILL.md +22 -7
  66. package/skills/ultra-init/SKILL.md +104 -59
  67. package/skills/ultra-init/references/brownfield-adoption.md +65 -37
  68. package/skills/ultra-plan/SKILL.md +20 -7
  69. package/skills/ultra-research/SKILL.md +12 -5
  70. package/skills/ultra-status/SKILL.md +6 -4
  71. package/skills/ultra-verify/SKILL.md +21 -30
  72. package/skills/ultra-verify/scripts/verify_wait.py +54 -54
  73. package/spec/cli-protocol.md +11 -1
  74. package/spec/mcp-tools.yaml +133 -19
  75. package/spec/schemas/state-db.sql +11 -0
  76. package/ultra-tools/cli.cjs +9 -5
  77. package/ultra-tools/commands/migrate.cjs +62 -36
  78. package/ultra-tools/commands/status.cjs +18 -9
  79. package/ultra-tools/commands/system.cjs +340 -6
  80. package/ultra-tools/commands/task.cjs +7 -1
  81. package/ultra-tools/status-command.test.cjs +29 -0
  82. package/ultra-tools/system-command.test.cjs +252 -1
  83. package/mcp-server/lib/llm-client.cjs +0 -157
  84. package/mcp-server/lib/llm-client.test.cjs +0 -156
  85. package/orchestrator/planner/expand-prompt.cjs +0 -62
  86. package/orchestrator/planner/expand-prompt.test.cjs +0 -52
  87. package/orchestrator/planner/prd-prompt.cjs +0 -44
  88. package/orchestrator/planner/prd-prompt.test.cjs +0 -30
@@ -78,9 +78,10 @@ necessary context when they do not.
78
78
  role, gate, readiness, blockers, and one next action. They must not inject intent
79
79
  bodies, transcripts, external memory, or graph payloads. Missing references,
80
80
  digest drift, HEAD drift, or a missing execution seam blocks readiness. Context
81
- size and an incomplete baseline are advisory during an active bounded change;
82
- baseline adoption becomes a hard gate at convergence; revision and tracked-spec
83
- integrity are reconciled and rechecked atomically at archive.
81
+ size and baseline drift are advisory for a change that is already active. New ordinary
82
+ work requires a healthy baseline. Only an explicitly approved incident break-glass may
83
+ start without it; incident archive records a blocking reconciliation gap. Revision and
84
+ tracked-spec integrity are reconciled and rechecked atomically for ordinary archive.
84
85
 
85
86
  Stable discoveries use `change.learning_propose`; they reach the baseline only
86
87
  through approve/reject/apply transitions in `change.learning_resolve`. Unresolved
@@ -112,8 +113,10 @@ the shared read-only `context_spine.py` breadcrumb helper:
112
113
  - `pre_stop_check.py` reports unfinished workflow position at stop without denial;
113
114
  - `subagent_tracker.py` for bounded worker lifecycle evidence.
114
115
 
115
- `workflow_context.py`, `active_task_context.py`, and `workflow_resume.py` read the
116
- same DB-derived breadcrumb through `context_spine.py`. `health_check.py` and
116
+ `workflow_context.py`, `active_task_context.py`, `workflow_resume.py`, and the
117
+ OpenCode plugin invoke the same bundled JavaScript `change.breadcrumb` reader
118
+ through the thin `context_spine.py` bridge. No hook reimplements the state query.
119
+ `health_check.py` and
117
120
  `workflow_context.py` may inspect any initialized project;
118
121
  `active_task_context.py` always protects the task projection but limits ordinary
119
122
  edit guidance to an active workflow. Compact/stop/subagent hooks remain
@@ -148,7 +151,8 @@ Archive before prune; the confirmation token is intentionally required.
148
151
  ```text
149
152
  .ultra/
150
153
  ├── state.db # authoritative SQLite store
151
- ├── workflow-state.json # active workflow/recovery checkpoint
154
+ ├── runtime/
155
+ │ └── checkpoint.json # advisory breadcrumb recovery projection
152
156
  ├── changes/
153
157
  │ ├── active/<id>/ # intent, delta, plan, context v2, learning, verification
154
158
  │ └── archive/ # converged packets after baseline reconciliation
@@ -74,7 +74,7 @@ covers seventeen tables:
74
74
 
75
75
  | Table | Holds | Phase |
76
76
  |--------------------|---------------------------------------------------|-------|
77
- | `baselines` | greenfield/brownfield adoption, specs, verification, unknowns, and approval | 11 |
77
+ | `baselines` | repository classification, greenfield/brownfield adoption, worktree snapshot, specs, evidence, verification, gap ledger, and approval | 12 |
78
78
  | `tasks` | task rows — id, status, deps, files_modified, … | 2 |
79
79
  | `events` | append-only event stream; `id` is subscription cursor (D31) | 2 |
80
80
  | `sessions` | execution sessions, **including lease + heartbeat fields** (D32) | 4.5 |
@@ -83,7 +83,7 @@ covers seventeen tables:
83
83
  | `telemetry` | per-session token / cost / tool-call counters | 6 |
84
84
  | `specs_refs` | spec change tracking → staleness propagation | 5 |
85
85
  | `circuit_breaker` | bounded retry and halt state for failed tasks | 5 |
86
- | `changes` | continuous feature/fix/incident lifecycle | 8C |
86
+ | `changes` | continuous feature/fix/incident lifecycle and incident baseline bypass | 12 |
87
87
  | `artifacts` | intent/context/verification artifact registry | 8C |
88
88
  | `context_snapshots`| role/gate context, readiness, budget, execution seam, hashes, git head, provider refs | 10 |
89
89
  | `spec_learning_candidates` | approval-gated implementation discoveries for baseline convergence | 10 |
@@ -128,23 +128,34 @@ archive/prune command for data created by older releases.
128
128
 
129
129
  ### Project baseline adoption
130
130
 
131
- `task.init_project` detects an empty repository as `greenfield` and an existing
132
- codebase as `brownfield` unless the caller supplies an explicit mode. It creates
133
- the same authoritative state shape without rewriting application code.
131
+ `task.init_project` classifies source, tests, deployment, persistence, package
132
+ scripts, and monorepo markers. It detects `greenfield` or `brownfield`, records
133
+ bounded classification evidence and selected repository scope, and creates the
134
+ same authoritative state shape without rewriting application code.
135
+
136
+ Projection-only v4.4 and v4.5 projects use `ultra-tools migrate` to preserve the
137
+ entire `.ultra` tree, import tasks and events, and create a `migrated/adopting`
138
+ compatibility row. Schema upgrades use `ultra-tools system doctor --repair` and
139
+ produce a pre-migration backup. Compatibility state never grants baseline approval;
140
+ `baseline.start` with `replace_migrated: true` opens the actual brownfield adoption.
134
141
 
135
142
  `baseline.start` opens adoption, `baseline.record` captures server-hashed spec
136
143
  references, bounded repository/runtime evidence, actual verification results,
137
- known unknowns, and metadata-only external provider references, and
144
+ known unknowns, repository branch and worktree snapshot, the categorized gap ledger,
145
+ and metadata-only external provider references, and
138
146
  `baseline.converge` records explicit owner approval. A ready baseline is replaced
139
147
  only by an explicit re-adoption, preserving the superseded row for recovery.
140
-
141
- With no active change, a missing, incomplete, or stale baseline routes to
142
- `ultra-init`. During an already active bounded fix or incident it is an advisory
143
- warning so recovery work remains possible. `change.converge` requires that adoption
144
- has produced a `ready` baseline, but does not reject the HEAD or tracked-spec drift
145
- created by the change itself. `change.archive` declares baseline updates, refreshes
146
- the revision and digests, rechecks full baseline health inside the same transaction,
147
- and rolls back both state and artifacts if reconciliation remains incomplete.
148
+ For a selected monorepo scope, the worktree digest and dirty-file list include only
149
+ that scope; out-of-scope changes remain visible repository context but cannot be
150
+ accepted implicitly by `accept_dirty_worktree`.
151
+
152
+ New ordinary changes require a healthy `ready` baseline. A change that was already
153
+ active may continue with baseline drift surfaced as a warning. A new incident can
154
+ start on an unhealthy baseline only with an explicit reason and approver stored in
155
+ `baseline_bypass_json`. Ordinary convergence and archive reconcile HEAD, worktree,
156
+ and tracked-spec drift atomically. Break-glass incident archive creates an open
157
+ blocking reconciliation gap, so incident recovery can finish without falsely marking
158
+ the project baseline healthy.
148
159
 
149
160
  ## 4. Continuous changes — the daily unit of convergence
150
161
 
@@ -179,10 +190,17 @@ checking, review, convergence, and recovery. Each snapshot records:
179
190
  - one deterministic next action.
180
191
 
181
192
  `change.breadcrumb` derives the compact current position from state.db. Session,
182
- edit, and resume hooks inject only this breadcrumb, never the intent body,
193
+ edit, resume, and OpenCode lifecycle hooks invoke one bundled read-only reader
194
+ and inject only this breadcrumb, never the intent body,
183
195
  provider content, or a conversation summary. A changed git HEAD marks the
184
196
  snapshot stale and routes back to `change.context`.
185
197
 
198
+ PRD decomposition and complex-task subdivision use the active host model. The
199
+ MCP accepts the resulting structured tasks, validates schema, topology,
200
+ baseline/change ownership, and transaction boundaries, then persists them. It
201
+ does not call Anthropic, OpenAI, or another model provider and needs no separate
202
+ model API credential.
203
+
186
204
  File count, token estimate, and context-share overflow produce warnings, never a
187
205
  refusal. The agent may narrow reads, load files lazily, or split a slice when that
188
206
  preserves correctness; it must not raise a threshold merely to clear a gate or
@@ -204,8 +222,13 @@ evidence, and final convergence decision.
204
222
 
205
223
  Mutating MCP calls enqueue durable `projection_jobs`. Success is exposed in MCP
206
224
  response metadata; failure becomes a retryable structured incident instead of a
207
- swallowed warning. `system.doctor` is read-only by default and performs only
208
- backup-first mechanical recovery when explicitly requested.
225
+ swallowed warning. `system.doctor` is read-only by default. Explicit repair performs
226
+ backup-first schema upgrade, archive-journal recovery, session and projection
227
+ recovery, and regenerated projections. It cannot approve a baseline or replace a
228
+ corrupt SQLite file silently. `system restore` accepts only a verified SQLite backup
229
+ inside `.ultra/backups`, quarantines the corrupt authority, and rolls back on failure.
230
+ When no valid backup exists, confirmed `system rebaseline` preserves both corrupt
231
+ authority and the legacy task projection before creating a new brownfield adoption.
209
232
 
210
233
  ## 5. Sessions — the execution unit
211
234
 
@@ -1,6 +1,6 @@
1
1
  # ultra-builder-pro-cli — 历史执行计划与决策日志
2
2
 
3
- > **2026-07-18 当前生效边界(D50-D54,覆盖下文旧 Phase 6/7 的内置图谱、memory 与 runtime 设计)**:
3
+ > **2026-07-18 当前生效边界(D50-D55,覆盖下文旧 Phase 6/7 的内置图谱、memory 与 runtime 设计)**:
4
4
  > Ultra Builder Pro 不再拥有 `memory.*`、recall、prompt/transcript/observation/summary
5
5
  > 收集 hook 或私有 agent memory。跨会话记忆全部交给独立安装的 cloud-mem/claude-mem。
6
6
  > 插件只保留 12 个 Ultra 公共 workflow(新增 daily `ultra-change` 与诊断
@@ -10,8 +10,8 @@
10
10
  > Kimi Code 采用各自 native plugin 呈现,其他旧 runtime adapter 已退役。下文所有与此冲突的
11
11
  > memory/hindsight 章节仅作为历史实施记录,不再是当前需求或运行时契约。
12
12
 
13
- **当前状态**:v0.12.1;四宿主 native plugin、36 个 live MCP tool、
14
- schema 11.0(17 表)、portable Skill authoring contract、双轴 review、
13
+ **当前状态**:v0.13.0;四宿主 native plugin、36 个 live MCP tool、
14
+ schema 12.0(17 表)、portable Skill authoring contract、双轴 review、
15
15
  Context Spine v2 / breadcrumb / spec-learning、持续 change/context/convergence/doctor、incident debug lane、
16
16
  checkpoint 恢复消费与跨宿主安装 provenance/doctor 已落地;npm 发布由
17
17
  `v*.*.*` tag 触发。以下 Phase 0-9 正文保留为 2026-04 的实施历史,不再作为
@@ -29,7 +29,7 @@ checkpoint 恢复消费与跨宿主安装 provenance/doctor 已落地;npm 发
29
29
  - **Phase 4.6 拆 a/b**(R6 + D35):v0.1 只跑 smoke flow,full conformance 推 v0.2
30
30
  - **Codex 第二轮结论**:"小改后开工"(tl;dr);本版已完成小改
31
31
 
32
- **总决策数**:D1-D53(当前边界以 D50-D53 为准)
32
+ **总决策数**:D1-D55(当前边界以 D50-D55 为准)
33
33
  **总风险数**:R1-R32(v0.3.1 新增 R25-R32 共 8 条)
34
34
 
35
35
  ---
@@ -1643,6 +1643,7 @@ Week 18 buffer(ship 中任何 Phase 的 25% 滑动吃掉)
1643
1643
  | **D52** | **2026-07-17** | **初始交付后进入持续变更闭环**:新增 `ultra-change` / `ultra-doctor`、change/context/artifact/trace/incident/projection/consumer 状态、delta-first spec、确定性 convergence 与 baseline reconciliation;删除内置 code-graph watcher 和通用命令代理,Memory/图谱只保留外部 provider 元数据引用 | 用户确认采用最佳组合落地;解决日常小改导致 spec/context 漂移、投影失败静默和异常无恢复证据的问题 |
1644
1644
  | **D53** | **2026-07-17** | **Harness 缺口一次性闭环**:`incident` 成为带五段 `diagnosis.md` 结构门禁的 canonical debug lane;compact checkpoint 由 resume 消费、校验、择新并原子恢复;三宿主安装写 normalized provenance,`ubp --doctor` 只读校验 asset hash 与 plugin/hook/MCP/runtime contract | 将 GSD 的 debug/fresh context、GStack 的 checkpoint/readiness 与 ECC 的 doctor/provenance 思路收敛为 Ultra 自有契约;Memory 与图谱继续由外部 provider 所有,且不恢复任何已退役 surface |
1645
1645
  | **D54** | **2026-07-18** | **老项目接入与非阻断门禁闭环**:schema 11.0 新增 greenfield/brownfield baseline authority 与 `baseline.start/record/get/converge`;`task.init_project` 自动识别新旧仓库;上下文文件数、token 和占比改为 advisory warning,active change 的 baseline 问题同样只告警,`change.converge` / delivery 恢复硬门禁 | 避免 Ultra 把既有项目当新产品,也避免必要的 IM incident 因四个大文件超预算而无法施工;限制只在损坏权威、缺少执行契约、证据陈旧和最终收敛边界阻断 |
1646
+ | **D55** | **2026-07-18** | **新项目、老项目与旧版 Ultra 接入完成统一闭环**:schema 12.0 增加 repository branch/worktree digest、classification、gap ledger 与 incident bypass authority;`ultra-init` 自动分类、resume 只补缺失 scaffold、projection-only state 走支持的备份式 import、旧 DB 备份后升级、migrated baseline 必须显式 brownfield replacement;普通新 change 要求 ready baseline,已开工 change 保持可执行,紧急 incident 只允许有审批记录的 break-glass 并在 archive 写阻断 reconciliation gap | 老项目不再被重置或伪装成 greenfield/ready;历史任务、事件与文档可恢复迁移;健康项目可直接进入日常 change,损坏权威停在明确的 restore-or-rebaseline 决策边界 |
1646
1647
 
1647
1648
  ---
1648
1649
 
package/docs/ROADMAP.md CHANGED
@@ -70,7 +70,7 @@ ultra-tools/ ← CLI fallback, migration, and diagnostics
70
70
  ├── cli.cjs
71
71
  └── commands/
72
72
  ├── db.cjs (init/checkpoint/vacuum/integrity/backup)
73
- ├── migrate.cjs (v4.4 → v4.5 + dry/rollback)
73
+ ├── migrate.cjs (v4.4 projection → v4.5 authority; v4.5 projection → schema 12; dry/rollback)
74
74
  └── legacy-memory.cjs (explicit inspect/archive/confirmed prune)
75
75
 
76
76
  bin/install.js ← multi-runtime installer
@@ -101,5 +101,5 @@ npm audit
101
101
  ## Out of scope for v1.0 (deferred)
102
102
 
103
103
  PLAN §13 lists Copilot / Cursor / Windsurf / 7 more runtimes, web
104
- dashboard / TUI, LLM provider abstraction, team-collab server, plugin
104
+ dashboard / TUI, team-collab server, plugin
105
105
  marketplace.
@@ -46,7 +46,7 @@ not presented as nonexistent custom agents.
46
46
 
47
47
  | Lifecycle | Claude Code | OpenCode | Codex | Kimi Code 0.26+ |
48
48
  |---|---|---|---|---|
49
- | Session context/health | FULL, DB-derived Context Spine breadcrumb on native `SessionStart` | DEGRADED, projected v2 breadcrumb; health via `system.doctor` | FULL, DB-derived breadcrumb on native `SessionStart` | FULL, DB-derived breadcrumb via session-start skill + hooks |
49
+ | Session context/health | FULL, DB-derived Context Spine breadcrumb on native `SessionStart` | FULL, the native JS plugin invokes the same bundled DB breadcrumb reader; health via `system.doctor` | FULL, DB-derived breadcrumb on native `SessionStart` | FULL, DB-derived breadcrumb via session-start skill + hooks |
50
50
  | Active edit boundary | FULL, `PreToolUse Edit|Write` | FULL, `tool.execute.before` rejects projection writes | FULL, `PreToolUse Edit|Write|apply_patch` | FULL, native `PreToolUse Edit|Write` deny contract |
51
51
  | Pre-compact checkpoint | FULL | FULL | FULL | FULL, native `PreCompact` |
52
52
  | Post-compact context injection | FULL | FULL, native compacting context | FULL, native `PostCompact` restore | DEGRADED; checkpoint restoration runs, but Kimi 0.26/0.27 does not reinject fire-and-forget hook text |
@@ -73,7 +73,7 @@ they do not deny edits or stop active incident work.
73
73
  | stdio MCP registration | plugin `.mcp.json` | `opencode.json` local MCP entry | plugin `.mcp.json` | plugin `mcpServers` entry |
74
74
  | Live/declared contracts | 36 | 36 | 36 | 36 |
75
75
  | Greenfield/brownfield baseline adoption | FULL | FULL | FULL | FULL |
76
- | Context Spine v2 / breadcrumb | FULL | FULL, DB-generated projection consumed by native JS | FULL | FULL |
76
+ | Context Spine v2 / breadcrumb | FULL | FULL, same bundled read-only DB reader as every hook | FULL | FULL |
77
77
  | Approval-gated spec learning | FULL | FULL | FULL | FULL |
78
78
  | Host-native review/discovery/ask | native | native | documented in `codex-capability-map.json` | native Kimi tools and workers |
79
79
  | Durable authority | project `.ultra/state.db` | project `.ultra/state.db` | project `.ultra/state.db` | project `.ultra/state.db` |
@@ -126,9 +126,9 @@ records. Uninstall refuses an unmanaged or conflicting root.
126
126
 
127
127
  | Capability | Contract |
128
128
  |---|---|
129
- | Current state schema | `11.0` |
129
+ | Current state schema | `12.0` |
130
130
  | Runtime values | `claude`, `opencode`, `codex`, `kimi` |
131
- | Upgrade from earlier schema | preserves runtime rows, adds Context Spine state through 10.0, then adds authoritative baseline adoption state transactionally in 11.0 |
131
+ | Upgrade from earlier schema | preserves runtime rows, adds Context Spine state through 10.0, authoritative baseline adoption in 11.0, then runtime constraint compatibility in 12.0 |
132
132
  | Preservation gate | rows, IDs, indexes, foreign keys, telemetry, incidents, and migration history remain intact |
133
133
  | Failure behavior | rollback; no partially upgraded authority database |
134
134
 
@@ -70,7 +70,7 @@ Detection happens at boot: `statvfs` of `.ultra/state.db`'s mount;
70
70
 
71
71
  | Table | Writer of record |
72
72
  |--------------------|--------------------------------------------------------|
73
- | `baselines` | MCP server (`baseline.start` / `baseline.record` / `baseline.converge`); initialization CLI may create the first row |
73
+ | `baselines` | MCP server (`baseline.start` / `baseline.record` / `baseline.converge`); initialization and legacy-projection migration may create only the first draft or compatibility row |
74
74
  | `tasks` | MCP server (`task.create` / `task.update` / `task.delete`) |
75
75
  | `changes` | MCP server (`change.create` / `change.update` / `change.converge` / `change.archive`) |
76
76
  | `artifacts`, `context_snapshots`, `spec_learning_candidates`, `trace_links` | MCP server through change lifecycle tools |
@@ -79,8 +79,8 @@ Detection happens at boot: `statvfs` of `.ultra/state.db`'s mount;
79
79
  | `sessions` | MCP server (`session.spawn` / `session.close` / `session.heartbeat`); orchestrator may write status transitions |
80
80
  | `telemetry` | MCP server (collected from tool-call wrappers); orchestrator may dump bulk samples |
81
81
  | `specs_refs` | MCP server (rebuilt on `spec_changed` event); orchestrator may rebuild |
82
- | `migration_history`| `ultra-tools migrate` CLI only |
83
- | `schema_version` | `ultra-tools db init` and `ultra-tools migrate` only |
82
+ | `migration_history`| schema initializer and `ultra-tools migrate` or doctor repair |
83
+ | `schema_version` | schema initializer, `ultra-tools db init`, migration, and doctor repair |
84
84
 
85
85
  ## 5. Forbidden patterns
86
86
 
@@ -22,10 +22,11 @@ host receives only its native invocation and collaboration names.
22
22
 
23
23
  The managed block deliberately stays short. It says that `.ultra/state.db` is
24
24
  authoritative; `change.context` compiles role/gate readiness, bounded references,
25
- fresh-context budget, public seam, and exact verification; size budgets and an
26
- incomplete baseline during active work are advisory, while an approved baseline is
27
- required for convergence and full baseline health is restored atomically at archive;
28
- hooks inject only the DB-derived
25
+ fresh-context budget, public seam, and exact verification; size budgets are advisory,
26
+ new ordinary work requires a healthy baseline, existing active work may continue with
27
+ warnings, and only an approved incident break-glass may start without baseline
28
+ readiness; ordinary archive restores baseline health while break-glass archive records
29
+ a blocking reconciliation gap; hooks inject only the DB-derived
29
30
  `change.breadcrumb`; and unresolved specification learning or either failed review
30
31
  axis blocks convergence. Detailed procedures remain in the plugin skills so user
31
32
  handbooks do not accumulate duplicated prompt sediment.
@@ -2,13 +2,11 @@
2
2
  """Protect Ultra projections and restate an active task boundary before edits."""
3
3
 
4
4
  import json
5
- import sqlite3
6
5
  import sys
7
6
  from pathlib import Path
8
7
 
9
- from context_spine import read_breadcrumb, render_breadcrumb
8
+ from context_spine import ContextSpineError, find_root, read_breadcrumb, render_breadcrumb
10
9
 
11
- TERMINAL = {"committed", "completed", "done", "cancelled"}
12
10
  TASKS_PROJECTION = Path(".ultra/tasks/tasks.json")
13
11
 
14
12
 
@@ -34,58 +32,32 @@ def main() -> None:
34
32
  except json.JSONDecodeError as exc:
35
33
  print(f"[active_task_context] invalid hook input: {exc}", file=sys.stderr)
36
34
  data = {}
37
- start = Path(data.get("cwd") or Path.cwd()).resolve()
38
- for root in (start, *start.parents):
39
- ultra = root / ".ultra"
40
- state_file = ultra / "workflow-state.json"
41
- initialized = (
42
- (ultra / "state.db").is_file()
43
- or state_file.is_file()
44
- or (ultra / "changes" / "active").is_dir()
45
- )
46
- if not initialized:
47
- continue
48
- if targets_tasks_projection(data, root):
49
- print(json.dumps({"hookSpecificOutput": {
50
- "hookEventName": "PreToolUse",
51
- "permissionDecision": "deny",
52
- "permissionDecisionReason": (
53
- "Refusing a direct write to the .ultra/tasks/tasks.json projection. "
54
- ".ultra/state.db is authoritative; use the Ultra MCP task tools and "
55
- "run ultra-doctor when state or projection health is degraded."
56
- ),
57
- }}))
58
- return
59
- try:
60
- breadcrumb = read_breadcrumb(root)
61
- except (sqlite3.Error, OSError) as exc:
62
- print(f"[active_task_context] cannot inspect Context Spine: {exc}", file=sys.stderr)
63
- breadcrumb = None
64
- if breadcrumb and breadcrumb.get("task_id"):
65
- print(json.dumps({"hookSpecificOutput": {
66
- "hookEventName": "PreToolUse",
67
- "additionalContext": render_breadcrumb(root, breadcrumb),
68
- }}))
69
- return
70
- if not state_file.is_file():
71
- break
72
- try:
73
- state = json.loads(state_file.read_text(encoding="utf-8"))
74
- except (OSError, json.JSONDecodeError) as exc:
75
- print(f"[active_task_context] cannot read {state_file}: {exc}", file=sys.stderr)
76
- break
77
- if not isinstance(state, dict) or state.get("status") in TERMINAL:
78
- break
79
- task = state.get("task_id", state.get("task", "unknown"))
80
- step = state.get("step", "unknown")
35
+ root = find_root(Path(data.get("cwd") or Path.cwd()).resolve())
36
+ if root is None:
37
+ print(json.dumps({}))
38
+ return
39
+ if targets_tasks_projection(data, root):
81
40
  print(json.dumps({"hookSpecificOutput": {
82
41
  "hookEventName": "PreToolUse",
83
- "additionalContext": (
84
- f"Active Ultra task {task}, step {step}. Keep this edit inside the approved "
85
- "task and preserve .ultra/state.db as workflow authority."
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."
86
47
  ),
87
48
  }}))
88
49
  return
50
+ try:
51
+ breadcrumb = read_breadcrumb(root)
52
+ except ContextSpineError as exc:
53
+ print(f"[active_task_context] cannot inspect Context Spine: {exc}", file=sys.stderr)
54
+ breadcrumb = None
55
+ if breadcrumb and breadcrumb.get("change_id"):
56
+ print(json.dumps({"hookSpecificOutput": {
57
+ "hookEventName": "PreToolUse",
58
+ "additionalContext": render_breadcrumb(root, breadcrumb),
59
+ }}))
60
+ return
89
61
  print(json.dumps({}))
90
62
 
91
63