ultra-builder-pro-cli 0.26.1 → 0.26.2

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 (39) hide show
  1. package/.ultra-template/north-star.md +20 -31
  2. package/.ultra-template/project-brief.md +28 -0
  3. package/.ultra-template/specs/product.md +4 -0
  4. package/.ultra-template/specs/research-distillate.md +8 -0
  5. package/.ultra-template/test-report.json +1 -0
  6. package/CHANGELOG.md +64 -0
  7. package/README.md +60 -28
  8. package/docs/ARCHITECTURE.md +32 -9
  9. package/docs/ARTIFACT-AUTHORITY.md +42 -13
  10. package/docs/DECISIONS.md +20 -3
  11. package/docs/PHILOSOPHY.md +9 -7
  12. package/docs/SKILL-AUTHORING.md +10 -6
  13. package/docs/WORKFLOW-LIFECYCLE.md +99 -39
  14. package/hooks/README.md +7 -2
  15. package/hooks/_common.py +54 -5
  16. package/hooks/session_context.py +34 -8
  17. package/package.json +1 -1
  18. package/skills/ultra-change/SKILL.md +52 -63
  19. package/skills/ultra-change/references/change-contract.md +37 -5
  20. package/skills/ultra-delegate/SKILL.md +14 -3
  21. package/skills/ultra-deliver/SKILL.md +48 -43
  22. package/skills/ultra-deliver/references/baseline-reconciliation.md +5 -3
  23. package/skills/ultra-dev/SKILL.md +8 -8
  24. package/skills/ultra-grilling/SKILL.md +9 -9
  25. package/skills/ultra-init/SKILL.md +62 -87
  26. package/skills/ultra-init/references/brownfield-adoption.md +23 -40
  27. package/skills/ultra-plan/SKILL.md +29 -18
  28. package/skills/ultra-research/SKILL.md +91 -68
  29. package/skills/ultra-research/references/{03-competitive-landscape.md → 03-alternatives.md} +6 -6
  30. package/skills/ultra-research/references/22-success-metrics.md +8 -4
  31. package/skills/ultra-research/references/99-synthesis.md +8 -1
  32. package/skills/ultra-research/references/wayfinding.md +42 -0
  33. package/skills/ultra-review/SKILL.md +4 -1
  34. package/skills/ultra-status/SKILL.md +62 -32
  35. package/skills/ultra-tdd/SKILL.md +5 -2
  36. package/skills/ultra-test/SKILL.md +26 -12
  37. package/skills/ultra-test/scripts/worktree_digest.cjs +42 -8
  38. package/skills/ultra-think/SKILL.md +5 -10
  39. package/skills/ultra-think/references/interaction-boundary.md +2 -1
@@ -43,9 +43,11 @@ one or more.
43
43
 
44
44
  ### C1 — Goal-Always-Present
45
45
 
46
- The agent never stops seeing the north-star. Every hook trigger that costs context budget injects:
47
- the project one-liner plus the current task's acceptance criteria. The cost of repetition is
48
- always less than the cost of drift.
46
+ The agent never stops seeing the current steering contract. Before Research accepts a
47
+ baseline, the session Hook injects the raw Project Brief fallback. After Research, it
48
+ injects the accepted North Star: Project Direction, any settled North Star Outcome, and
49
+ Hard Constraints. Current task acceptance is appended in both cases. The cost of
50
+ repetition is always less than the cost of drift.
49
51
 
50
52
  > **Test**: pick a random in-progress task, ask the agent "what's the acceptance criteria?" — if
51
53
  > it cannot answer in one sentence, this commandment is broken.
@@ -185,15 +187,15 @@ Skill instruction. Do not touch it casually.
185
187
 
186
188
  | Consumer | Reads | Source of truth | Failure mode if drifted |
187
189
  |---|---|---|---|
188
- | `session_context` | headings `## One-line`, `## Hard Constraints` | `.ultra-template/north-star.md` | SessionStart shows no goal; C1 dies |
189
- | `session_context` | active `in_progress` task → its context | `tasks.json[].context_file` | acceptance criteria never surfaced |
190
+ | `session_context` | North Star headings `## Project Direction`, `## North Star Outcome`, `## Hard Constraints`; Project Brief `## One-line`, or legacy North Star `## One-line` | `.ultra-template/north-star.md`, `.ultra-template/project-brief.md`, and the Hook's legacy-read branch | SessionStart shows no accepted North Star or Project Brief fallback; C1 dies |
191
+ | `session_context` | unique active `change_id` → one matching `in_progress` task, else first dependency-ready `pending` task → its context | active Change directory plus `tasks.json[].change_id`, dependencies, status, and `context_file` | abandoned or blocked acceptance is injected, or current acceptance never surfaces |
190
192
  | `mid_workflow_recall` | heading `## Acceptance Criteria` | `.ultra-template/contexts/TEMPLATE.md` | hook injects nothing; C1 dies silently |
191
193
  | `ultra-tdd` | path `references/templates/*` | `skills/ultra-tdd/references/templates/` | guidance points at a missing runnable alternative; C2 dies |
192
- | `post_edit_guard` | writes `.ultra/progress/<task-id>.json` | `tasks.json[].id`, created on demand | mechanical observations disappear; C4 weakens |
194
+ | `post_edit_guard` | writes `.ultra/progress/<task-id>.json` for the active Change's current task | active Change directory plus `tasks.json[].change_id` and `id`, created on demand | historical work receives current observations; C4 weakens |
193
195
  | `ultra-dev` and `post_edit_guard` | 6 keys: `tests_written`, `tests_passed`, `persistence_real`, `feature_flags_audit`, `vertical_slice`, `spec_trace` | the six-dimension table in `skills/ultra-dev/SKILL.md` | sensor and workflow report different evidence |
194
196
  | planning and status | marker `[NEEDS CLARIFICATION]` | `.ultra-template/specs/*.md` | unresolved product truth is hidden |
195
197
  | `ultra-plan` / `ultra-dev` / hooks | `trace_to` form `.ultra/specs/file.md#anchor` | `tasks.json[].trace_to` + GFM heading slugify | traces appear resolved when their heading is absent |
196
- | `ultra-deliver` / `ultra-status` | field `git_commit` | `.ultra/test-report.json` | stale test results pass as current |
198
+ | `ultra-deliver` / `ultra-status` | fields `change_id`, `task_ids`, `intent_digest`, `git_commit`, and `worktree.diff_digest` | `.ultra/test-report.json` plus `worktree_digest.cjs` | stale Change, intent, task set, or product results pass as current |
197
199
  | `compact_context` | `.ultra/.runtime/compact-snapshot.md` | derived from canonical files and Git | compact recovery loses acceleration, not authority |
198
200
  | every hook | existence of `.ultra/` | the project directory | Ultra taxes projects that never opted in (see `docs/PLUGIN-ISOLATION-CONTRACT.md`) |
199
201
  | `ultra-init` | the project data skeleton | `.ultra-template/` and the exact file list in its Skill | later Skills read missing authority paths; C1 dies |
@@ -41,14 +41,15 @@ Every Skill has one outcome-led title and these semantic sections:
41
41
  ## References
42
42
  ```
43
43
 
44
- User workflows begin by reading `.ultra/tasks.json`, the unfinished task's
45
- `context_file` and Resume Note, `CONTEXT.md`, and relevant decisions. They name the
46
- files they write and read them back. Completion criteria must be observable without a
47
- semantic validator.
44
+ User workflows first resolve at most one active `change_id`, then read only matching
45
+ rows from `.ultra/tasks.json`, the frontier task's `context_file` and Resume Note,
46
+ `CONTEXT.md`, and relevant decisions. Historical or abandoned rows never become current
47
+ from status alone. They name the files they write and read them back. Completion
48
+ criteria must be observable without a semantic validator.
48
49
 
49
50
  Use positive leading words consistently: tracer bullet, seam, deep module, red,
50
- frontier, and fog of war. Explain a branch by its checkable result, not the model's
51
- reason for choosing it.
51
+ frontier, and research boundary. Explain a branch by its checkable result, not the
52
+ model's reason for choosing it.
52
53
 
53
54
  ## Progressive disclosure
54
55
 
@@ -56,6 +57,9 @@ Keep resident `SKILL.md` short enough to load on every invocation. Move focused
56
57
  into `references/` and deterministic validation or waiting into `scripts/`.
57
58
 
58
59
  - Load one research step or review lens at a time.
60
+ - Keep Research's semantic lenses and optional Wayfinding map inside
61
+ `ultra-research/references/`; they are stages of that public workflow, not reusable
62
+ model-invoked Skills.
59
63
  - Keep one canonical copy of grilling, TDD, review, domain language, and autonomy rules.
60
64
  - Cross-reference another model-invoked Skill by relative path.
61
65
  - Do not hide the primary workflow in a script.
@@ -6,9 +6,9 @@ criteria; repository files record facts; the host model chooses the route.
6
6
  ## Capability flow
7
7
 
8
8
  ```text
9
- ultra-init
10
- ├─ unresolved external claims ─► ultra-research
11
- └─ bounded requested outcome ──► ultra-change
9
+ ultra-init ──raw Project Brief──► ultra-research ──accepted baseline──► ultra-change
10
+ ▲ │
11
+ └──── scoped consequential evidence gap ────┘
12
12
 
13
13
  ultra-change ─► ultra-plan ─► ultra-dev (per task) ─► ultra-test ─► ultra-deliver
14
14
  ▲ │ │
@@ -19,51 +19,78 @@ ultra-delegate orthogonal bounded execution on another CLI
19
19
  ```
20
20
 
21
21
  Arrows are recommendations, not automatic invocation. The owner explicitly selects
22
- each public workflow.
22
+ each public workflow. Delivery archives one stable `change_id`; the next request opens
23
+ a new active id while prior task rows remain in the append-only ledger.
23
24
 
24
25
  ## Common entry contract
25
26
 
26
27
  Every user-invoked Skill reads, in order:
27
28
 
28
- 1. `.ultra/tasks.json`;
29
- 2. the unfinished task's `context_file` and closing `## Resume Note`;
30
- 3. `CONTEXT.md` and relevant `.ultra/decisions/`;
31
- 4. the active Change, specifications, evidence, and Git state relevant to its scope.
29
+ 1. zero or one `.ultra/changes/active/<change_id>/intent.md`; more than one is a conflict;
30
+ 2. `.ultra/tasks.json`, selecting only tasks whose `change_id` matches that active id;
31
+ 3. the matching frontier task's `context_file` and closing `## Resume Note`;
32
+ 4. `.ultra/project-brief.md`, the accepted `.ultra/north-star.md`, `CONTEXT.md`, and
33
+ relevant `.ultra/decisions/`, where those artifacts already exist;
34
+ 5. the active Change, specifications, evidence, maintained documentation, and Git state
35
+ relevant to its scope.
32
36
 
33
37
  Missing files produce a precise recovery or initialization recommendation. They do not
34
38
  cause the Skill to invent a state transition.
35
39
 
36
40
  ## Initialization
37
41
 
38
- `ultra-init` distinguishes owner authorization from claims requiring evidence. It
39
- creates the file skeleton, preserves unknowns as `[NEEDS CLARIFICATION]`, initializes
40
- Git when absent, and records only repository-observable brownfield facts. It does not
41
- perform research or launch another workflow.
42
+ Init writes the raw Project Brief and stable empty skeleton. `ultra-init` preserves the
43
+ owner's one-line request, broad outline, explicit inputs, and open questions without
44
+ turning them into validated product truth. It initializes Git when absent and may
45
+ preserve repository-observable brownfield facts as Research inputs. It does not define
46
+ success, establish the North Star, create `CONTEXT.md`, populate specifications, or
47
+ launch another workflow.
42
48
 
43
49
  ## Research
44
50
 
45
- `ultra-research` maps unresolved claims to the smallest useful subset of seventeen
46
- focused references. Reports are written immediately. Three material checkpoints can
47
- change later scope; the owner resolves those checkpoints. The final distillate records
48
- Git blob hashes of the specifications it summarizes.
51
+ Research turns the brief into an accepted North Star and evidence-backed baseline.
52
+ `ultra-research` uses Wayfinding only when a multi-lens path is unclear, then maps the
53
+ question to the smallest useful subset of seventeen focused references. The first six
54
+ are semantic lenses with real dependencies: `00` precedes `01`; conditional `02` and
55
+ `03` may fan out after the boundary is known; `04` consumes their relevant conclusions
56
+ and is the first owner checkpoint; `05` extracts assumptions from `00` through `04`.
57
+ Grilling controls how missing owner inputs are asked, Think tests one consequential
58
+ decision, and Domain Modeling writes settled vocabulary; none owns the Research route.
59
+ The final synthesis promotes accepted conclusions into the North Star, `CONTEXT.md`,
60
+ three specifications, and a source-hash-bound distillate.
49
61
 
50
62
  ## Change reconciliation
51
63
 
52
- `ultra-change` first compares requested behavior with product truth and current code.
53
- It classifies changes by the resulting commitments:
64
+ Change updates only the touched baseline rather than rebuilding it. `ultra-change`
65
+ first compares requested behavior with accepted product truth and current code. It
66
+ classifies changes by the resulting commitments:
54
67
 
55
68
  - expansion and correction may proceed inside accepted intent;
56
69
  - a reduction waits for explicit owner authority.
57
70
 
58
71
  The output is one active Change intent with observable outcome, acceptance, seams,
59
- non-goals, and trace anchors.
72
+ non-goals, trace anchors, and an explicit Research Disposition. `none` cites sufficient
73
+ existing evidence; `bounded` or `required` names the exact question, lenses, and exit
74
+ evidence. Unsatisfied exit evidence routes to Research, then back through Change
75
+ reconciliation before planning when the accepted contract needs an update.
76
+
77
+ A micro edit that makes no specification sentence false stays outside the Ultra
78
+ lifecycle and uses ordinary repository TDD/verification. Once an active Change exists,
79
+ even a `quick` profile receives one minimal Plan task so evidence and delivery remain
80
+ bound to its id. A separate request cannot open a second active Change: finish or
81
+ deliver the current one, abandon it with owner authority, or explicitly reconcile the
82
+ new request into the same stable id.
60
83
 
61
84
  ## Planning
62
85
 
63
- `ultra-plan` confirms the scope posture and public seams, then writes a task graph and
64
- one context file per task. Feature tasks are tracer bullets. A contract task precedes
65
- cross-process or cross-top-level-boundary implementations; integration checkpoints
66
- appear after several slices. Cycles and broken trace paths are repaired before handoff.
86
+ `ultra-plan` confirms a material scope posture and records public seams, then appends a
87
+ current-Change task graph and one context file per task without deleting historical
88
+ rows. The model chooses ordinary technical seams; the owner is asked only when a seam
89
+ changes a public contract, accepted risk, or another material trade-off. Every task
90
+ stores the stable `change_id`; dependencies stay inside that Change and ids remain
91
+ globally unique. Feature tasks are tracer bullets. A contract task precedes cross-process
92
+ or cross-top-level-boundary implementations; integration checkpoints appear after
93
+ several slices. Cycles and broken trace paths are repaired before handoff.
67
94
 
68
95
  ## Task development
69
96
 
@@ -78,15 +105,26 @@ duplication or coupling visible.
78
105
 
79
106
  ## Whole-system audit
80
107
 
81
- `ultra-test` runs once after the ledger is complete. It checks anti-patterns, coverage,
108
+ `ultra-test` runs once after tasks for the active Change are complete. It checks anti-patterns, coverage,
82
109
  wiring, E2E behavior, performance, and security. It names the exact Git commit and
83
- never turns an orphan, failed command, stub, or omission into permission to alter scope.
110
+ binds the report to `change_id`, exact current task ids, intent SHA-256, and the
111
+ product-worktree digest. `passed: true` implies complete current tasks and no required
112
+ area left `not_run`; task completion does not force a pass, and dispositioned gaps stay
113
+ visible. It never turns an orphan,
114
+ failed command, stub, or omission into permission to alter scope.
84
115
 
85
116
  ## Delivery
86
117
 
87
- `ultra-deliver` reconciles actual outcome, specifications, documentation, current test
88
- report, aggregate review, build, version impact, omissions, and rollback. It archives
89
- the Change with `git mv` after local reconciliation.
118
+ `ultra-deliver` uses two observable passes. The first reconciles actual outcome,
119
+ specifications, documentation, aggregate review, omissions, and rollback; if semantic
120
+ or product files change, it stops and recommends a fresh Test. The second begins only
121
+ when report Change/task/intent/HEAD/product identities match, applies the changed-export
122
+ gate, runs build and non-publishing package inspection, records version impact, writes
123
+ delivery metadata, and archives the same stable id with `git mv`. Delivery metadata and
124
+ the directory move do not invalidate their own product snapshot. Producing a release
125
+ package remains blocked while a changed export has neither a non-test consumer nor an
126
+ owner disposition. That disposition is recorded against the finding in the current
127
+ test report without changing the finding or `passed`, then carried into `delivery.md`.
90
128
 
91
129
  Commit, push, tag, publication, release, and deployment are independent external
92
130
  effects. Readiness grants none automatically.
@@ -95,27 +133,44 @@ effects. Readiness grants none automatically.
95
133
 
96
134
  `ultra-status` infers the smallest next route from observable files:
97
135
 
98
- - no healthy skeleton → init;
99
- - unresolved evidence-bearing claim → research;
136
+ - no healthy skeleton or usable raw brief → init;
137
+ - raw brief without an accepted baseline, or a consequential evidence gap → research;
100
138
  - requested outcome without active Change → change;
101
- - active Change without executable ledger → plan;
102
- - pending or in-progress task → dev;
103
- - completed ledger without current report → test;
104
- - current report and unarchived Change → deliver.
139
+ - draft or blocking active intent → change;
140
+ - unsatisfied Research Disposition → research;
141
+ - active Change without matching executable tasks → plan;
142
+ - matching pending or in-progress task → dev;
143
+ - completed current-Change tasks without a matching fresh report → test;
144
+ - false report → route by finding and owner disposition, not by the boolean alone;
145
+ - fresh, dispositioned report and unarchived Change → deliver.
105
146
 
106
147
  It also checks installation provenance, stale reports, old in-progress work, and
107
148
  unresolved markers. It does not mutate artifacts.
108
149
 
150
+ ## Delegation
151
+
152
+ `ultra-delegate` is orthogonal to the lifecycle and requires explicit owner authority.
153
+ Its immutable instruction selects task execution/continuation, scoped Research evidence,
154
+ or aggregate Change review/verification. Task execution reads one matching task context;
155
+ the latter two may be read-only and do not require a task, so both pre-Plan evidence and
156
+ post-task review remain reachable. Every scope still binds the one active `change_id`, a
157
+ clean isolated worktree, strict permission/result schemas, and primary-host inspection.
158
+ The worker cannot write canonical `.ultra` files or perform external effects.
159
+
109
160
  ## Artifact closure
110
161
 
111
162
  Every durable output has a later reader:
112
163
 
113
- - init's north star and specification skeletons are read by all later workflows;
114
- - research reports are traced into specifications, Change reconciliation, planning,
164
+ - init's Project Brief is consumed by Research, Status, and the pre-baseline session
165
+ Hook fallback; its empty skeleton supplies stable paths rather than product claims;
166
+ - Research's accepted North Star and domain/specification baseline are read by every
167
+ later workflow, while selected reports trace into Change reconciliation, planning,
115
168
  and delivery;
116
- - Change intent is consumed through planning, development, audit, review, status, and
117
- delivery;
118
- - task ledger and contexts are the common resume input, while task evidence feeds
169
+ - active Change intent and its touched specification deltas are consumed through
170
+ planning, development, audit, review, status, and delivery; an abandoned intent has
171
+ an exact `## Abandonment` closure consumed by future Change reconciliation and Status;
172
+ - the append-only task ledger and contexts are the common resume input after filtering
173
+ by active `change_id`, while task evidence feeds
119
174
  review, whole-system audit, and delivery;
120
175
  - the current test report is consumed by status and delivery;
121
176
  - delivery moves with the Change into archive and remains historical evidence.
@@ -126,6 +181,11 @@ an unowned drift log, Change plan, technical-debt report, or second delivery sum
126
181
 
127
182
  ## Interruption and cross-host continuation
128
183
 
184
+ There is one primary writer for canonical `.ultra` files. Review workers are read-only;
185
+ delegated source edits use isolated worktrees and return results for explicit
186
+ integration. Parallel canonical writes are unsupported because silently merging intent,
187
+ task, evidence, or report authority would lose meaning.
188
+
129
189
  Before stopping, the active task context records current facts, exact verification,
130
190
  open questions, Completion, and a closing Resume Note. The next session or host repeats
131
191
  the common entry contract and compares the working tree with those claims.
package/hooks/README.md CHANGED
@@ -5,8 +5,8 @@ directory and exits silently when the workflow is not active.
5
5
 
6
6
  | Hook | Lifecycle | Purpose |
7
7
  |---|---|---|
8
- | `session_context.py` | Session start | Inject the one-line north star and current acceptance criteria |
9
- | `mid_workflow_recall.py` | Before source reads or edits | Restate current acceptance only |
8
+ | `session_context.py` | Session start | Inject the accepted North Star or Project Brief fallback, plus acceptance from the unique active Change's current task |
9
+ | `mid_workflow_recall.py` | Before source reads or edits | Restate acceptance only for a task matching the unique active `change_id` |
10
10
  | `compact_context.py` | Before/after compaction | Save and restore a disposable snapshot derived from files and Git |
11
11
  | `post_edit_guard.py` | After edits | Record mechanical evidence observations without deciding completion |
12
12
  | `block_dangerous_commands.py` | Before shell execution | Advise on additive protected-branch publication; block history rewrites and a narrow destructive set until the exact command is owner-authorized |
@@ -14,6 +14,11 @@ directory and exits silently when the workflow is not active.
14
14
  `_common.py` is a shared library, not a lifecycle registration. Compact snapshots and
15
15
  progress observations live under ignored `.ultra/.runtime/` or `.ultra/progress/`; the
16
16
  canonical semantic facts remain the owner-readable files and Git.
17
+ Legacy task rows with no `change_id` remain readable from an active-path `change_ref`
18
+ during migration; a present canonical `change_id` always wins, and archived or
19
+ abandoned paths are never revived as current work. Task
20
+ selection prefers the single `in_progress` row, then the first `pending` row whose
21
+ same-Change dependencies are complete; ambiguous concurrent work stays silent.
17
22
 
18
23
  Claude Code runs the hooks directly. Codex, Kimi Code, and Grok Build use the small
19
24
  wire adapters under `hooks/adapters/`. OpenCode calls the same scripts from its native
package/hooks/_common.py CHANGED
@@ -47,12 +47,61 @@ def read_tasks(root: Path) -> list[dict[str, Any]]:
47
47
  return [item for item in tasks if isinstance(item, dict)] if isinstance(tasks, list) else []
48
48
 
49
49
 
50
+ def active_change_id(root: Path) -> str | None:
51
+ active = root / ".ultra" / "changes" / "active"
52
+ try:
53
+ change_ids = sorted(
54
+ entry.name
55
+ for entry in active.iterdir()
56
+ if entry.is_dir() and (entry / "intent.md").is_file()
57
+ )
58
+ except OSError:
59
+ return None
60
+ if len(change_ids) != 1:
61
+ return None
62
+ change_id = change_ids[0]
63
+ return change_id if re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]*", change_id) else None
64
+
65
+
66
+ def legacy_task_change_id(task: dict[str, Any]) -> str | None:
67
+ value = task.get("change_ref")
68
+ if not isinstance(value, str):
69
+ return None
70
+ match = re.fullmatch(
71
+ r"(?:\.ultra/)?changes/active/([A-Za-z0-9][A-Za-z0-9._-]*)/intent\.md",
72
+ value,
73
+ )
74
+ return match.group(1) if match else None
75
+
76
+
50
77
  def current_task(root: Path) -> dict[str, Any] | None:
51
- tasks = read_tasks(root)
52
- for status in ("in_progress", "pending"):
53
- for task in tasks:
54
- if task.get("status") == status:
55
- return task
78
+ change_id = active_change_id(root)
79
+ if change_id is None:
80
+ return None
81
+ tasks = [
82
+ task for task in read_tasks(root)
83
+ if task.get("change_id") == change_id
84
+ or ("change_id" not in task and legacy_task_change_id(task) == change_id)
85
+ ]
86
+ in_progress = [task for task in tasks if task.get("status") == "in_progress"]
87
+ if len(in_progress) == 1:
88
+ return in_progress[0]
89
+ if len(in_progress) > 1:
90
+ return None
91
+ by_id = {task.get("id"): task for task in tasks if isinstance(task.get("id"), str)}
92
+ for task in tasks:
93
+ if task.get("status") != "pending":
94
+ continue
95
+ dependencies = task.get("dependencies", [])
96
+ if not isinstance(dependencies, list):
97
+ continue
98
+ if all(
99
+ isinstance(dependency, str)
100
+ and dependency in by_id
101
+ and by_id[dependency].get("status") == "completed"
102
+ for dependency in dependencies
103
+ ):
104
+ return task
56
105
  return None
57
106
 
58
107
 
@@ -1,22 +1,48 @@
1
1
  #!/usr/bin/env python3
2
- """Inject the one-line goal and current task acceptance at session start."""
2
+ """Inject the accepted North Star or its pre-Research fallback plus task acceptance."""
3
3
 
4
4
  from _common import current_task, emit_context, markdown_section, project_root, read_payload, task_sections
5
5
 
6
6
 
7
+ def settled_section(text: str) -> str:
8
+ """Return an explicitly populated section, not a packaged unresolved marker."""
9
+ if not text or "[NEEDS CLARIFICATION]" in text or "not yet defined" in text.lower():
10
+ return ""
11
+ return text.strip()
12
+
13
+
14
+ def read_text(file) -> str:
15
+ try:
16
+ return file.read_text(encoding="utf-8")
17
+ except OSError:
18
+ return ""
19
+
20
+
7
21
  def main() -> int:
8
22
  payload = read_payload()
9
23
  root = project_root(payload) # Idle guard: no `.ultra/` means silent exit.
10
24
  if root is None:
11
25
  return 0
12
- try:
13
- north_star = (root / ".ultra" / "north-star.md").read_text(encoding="utf-8")
14
- except OSError:
15
- north_star = ""
26
+ ultra = root / ".ultra"
27
+ north_star = read_text(ultra / "north-star.md")
28
+ project_brief = read_text(ultra / "project-brief.md")
16
29
  parts = []
17
- one_line = markdown_section(north_star, "One-line")
18
- if one_line:
19
- parts.append(f"Ultra north star:\n{one_line}")
30
+ direction = settled_section(markdown_section(north_star, "Project Direction"))
31
+ if direction:
32
+ baseline = [f"Project Direction:\n{direction}"]
33
+ for heading in ("North Star Outcome", "Hard Constraints"):
34
+ section = settled_section(markdown_section(north_star, heading))
35
+ if section:
36
+ baseline.append(f"{heading}:\n{section}")
37
+ baseline_text = "\n\n".join(baseline)
38
+ parts.append(f"Ultra accepted north star:\n{baseline_text}")
39
+ else:
40
+ brief_line = settled_section(markdown_section(project_brief, "One-line"))
41
+ legacy_line = settled_section(markdown_section(north_star, "One-line"))
42
+ if brief_line:
43
+ parts.append(f"Ultra project brief (Research not yet accepted):\n{brief_line}")
44
+ elif legacy_line:
45
+ parts.append(f"Ultra legacy project intent:\n{legacy_line}")
20
46
  task = current_task(root)
21
47
  if task:
22
48
  acceptance = task_sections(root, task)["acceptance"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultra-builder-pro-cli",
3
- "version": "0.26.1",
3
+ "version": "0.26.2",
4
4
  "description": "File-first Ultra Builder Pro workflows for Claude Code, OpenCode, Codex CLI, Kimi Code, and Grok Build.",
5
5
  "bin": {
6
6
  "ultra-builder-pro-cli": "bin/install.js",
@@ -1,59 +1,56 @@
1
1
  ---
2
2
  name: ultra-change
3
- description: Open one bounded unit of work by first reconciling what the specifications promise against what the code actually does, then writing the intent that closes the gap. Use when nothing is in flight and something new is being asked for — a feature, a fix, a redesign, or an incident response.
3
+ description: Open or reconcile one bounded unit of work by comparing specification promises with actual code, then writing the intent that closes the gap. Use when no Change is active and a feature, fix, redesign, or incident response is requested, or when an active Change's draft, researched evidence, or accepted boundary must be reconciled.
4
4
  ---
5
5
 
6
6
  # Reconcile first, then write down what this Change commits to
7
7
 
8
- A Change is the durable unit connecting research, plan, implementation,
9
- verification, review and delivery. Reconciliation comes first because writing new
10
- intent on top of specifications that already disagree with the code buries the
11
- disagreement instead of resolving it.
8
+ A Change connects research, plan, implementation, verification, review, and delivery.
9
+ Reconcile first so new intent does not bury an existing specification/code conflict.
12
10
 
13
11
  ## Before you start
14
12
 
15
- 1. Read `.ultra/tasks.json`, and the `context_file` of any task not yet finished.
16
- 2. Read `CONTEXT.md` for vocabulary and `.ultra/decisions/` for entries in scope.
17
- 3. Read `.ultra/north-star.md` — a Change that does not serve it is worth
18
- questioning out loud before it is written down.
19
- 4. Grep `.ultra/changes/archive/` for Changes that already touched this area. Read
20
- `delivery.md` when present; otherwise read `archive-summary.md`, `verification.md` and
21
- remaining owner-readable Markdown. A missing `delivery.md` does not mean no history;
22
- a module that keeps reappearing is an architecture signal.
13
+ 1. List `.ultra/changes/active/`; more than one `intent.md` is a conflict, not a choice.
14
+ One directory name is the stable `change_id`. Read `.ultra/tasks.json`, then only its
15
+ unfinished `context_file` values. Update the same `change_id`; never open a second active Change.
16
+ 2. Read `.ultra/project-brief.md`, `CONTEXT.md`, relevant `.ultra/decisions/`, and
17
+ `.ultra/north-star.md` for raw provenance, accepted language, and direction.
18
+ 3. Grep archive and abandoned Changes that touched this area. Prefer archived
19
+ `delivery.md`; otherwise read `archive-summary.md`, `verification.md`, `intent.md`,
20
+ and remaining Markdown. Read abandoned Changes as history of rejected boundaries and
21
+ reusable evidence, never current intent. A missing `delivery.md` does not mean no history;
22
+ repeated modules are an architecture signal.
23
23
 
24
24
  ## Whether this skill applies at all
25
25
 
26
26
  | Situation | Where it goes |
27
27
  |---|---|
28
- | No pending or in-progress task, and something new is asked for | Here |
28
+ | No active Change, and a new bounded request exists | Here — create one stable id |
29
+ | One active Change needs its draft, Research evidence, or accepted boundary reconciled | Here — update the same `change_id` |
30
+ | A separate request arrives while one Change remains active | Do not create a second Change; finish or deliver the current one, abandon it with owner authority, or explicitly fold the request into its boundary |
29
31
  | A task is in progress and the specification turns out not to match reality | Not here — the dual-write path inside `ultra-dev` |
30
- | The change makes no sentence in the specifications false | Neither — just make the change |
32
+ | The change makes no sentence in the specifications false | Outside the Ultra lifecycle — use ordinary repository TDD and verification |
31
33
 
32
- That third row is the checkable answer to "how small is too small to deserve a
33
- Change file": if nothing the specifications say becomes untrue, there is nothing
34
- to reconcile and nothing to record.
34
+ If no specification sentence becomes untrue, there is nothing to reconcile. Use
35
+ `../ultra-tdd/SKILL.md` when helpful, but create no Change artifacts or Ultra
36
+ Test/Deliver claim for that micro change.
35
37
 
36
38
  ## Definition of done
37
39
 
38
- - `.ultra/changes/active/<id>/intent.md` states the observable outcome, the
39
- executable acceptance, the non-goals, and the public seams touched.
40
- - Each of the three reconciliation buckets is either empty or dispositioned, with
41
- the owner's answer recorded for every bucket that was not empty.
42
- - The draft stays editable until then; the owner's acceptance is what turns it
43
- into authority.
40
+ - Active `intent.md` states outcome, executable acceptance, non-goals, public seams,
41
+ and Research Disposition.
42
+ - Every reconciliation bucket is empty or dispositioned with the owner's answer.
43
+ - The draft remains editable until owner acceptance makes it authority.
44
44
 
45
45
  ## Reconcile against a bounded scope
46
46
 
47
- A whole-repository diff is unusable, so derive the scope with four steps anyone
48
- can rerun:
47
+ A Change does not rebuild the project baseline; reconcile only the touched specification sections
48
+ and leave unrelated gaps visible with four rerunnable steps:
49
49
 
50
50
  1. Decide which specification sections this request touches.
51
- 2. For each section, collect the past tasks whose `trace_to` points at it, and
52
- from those the set of code files they changed.
53
- 3. `git log -- .ultra/specs/<file>` gives the commit where that specification
54
- last changed.
55
- 4. `git diff <that commit>..HEAD -- <those code files>` is the reconciliation
56
- scope.
51
+ 2. Collect past tasks whose `trace_to` points there and the code files they changed.
52
+ 3. Use `git log -- .ultra/specs/<file>` to find its last specification change.
53
+ 4. Inspect `git diff <that commit>..HEAD -- <those code files>`.
57
54
 
58
55
  Sort what you find into three buckets, each with your recommended disposition:
59
56
 
@@ -63,47 +60,39 @@ Sort what you find into three buckets, each with your recommended disposition:
63
60
  | Code implements it, no specification says so | Built and unpromised |
64
61
  | Both speak and they conflict | Contradictory |
65
62
 
66
- Take the buckets to the owner — confirmed rather than assumed, because a
67
- disposition can quietly withdraw a commitment. Sort by risk first and match the
68
- asking to it: anything that touches a `HC-<n>` hard constraint or removes
69
- something already promised goes one at a time with your recommendation; the
70
- remaining low-risk rows go as a single list with a recommended disposition each,
71
- for one confirmation. Twenty separate questions about rows that change nothing
72
- spends the owner's attention where it was not needed, and trains them to approve
73
- without reading.
63
+ Take non-empty buckets to the owner because disposition can withdraw a commitment.
64
+ Ask one recommended question per `HC-<n>` impact or removed promise; group remaining
65
+ low-risk rows into one recommended list for confirmation.
74
66
 
75
67
  ## Write the intent
76
68
 
77
- Read `references/change-contract.md` and use its exact `intent.md` headings. The active
78
- Change directory contains only this accepted contract until planning or delivery adds
79
- its defined artifacts; do not invent a parallel semantic record.
69
+ Read `references/change-contract.md` and use its exact headings. Until planning or
70
+ delivery, the active directory contains only this contract; add no parallel record.
80
71
 
81
- Follow `../ultra-grilling/SKILL.md` to settle the boundary — one question at a
82
- time, each with your recommendation. New domain terms go through
83
- `../ultra-domain-modeling/SKILL.md`.
72
+ Use `../ultra-grilling/SKILL.md` to settle the boundary and
73
+ `../ultra-domain-modeling/SKILL.md` for new domain terms.
84
74
 
85
- When the work is too large *and* the path itself is unclear, follow
86
- `../ultra-think/SKILL.md` for a decision ticket instead of forcing a task
87
- breakdown. What comes out is a question whose answer is a decision, not an
88
- implementation slice.
75
+ Use `../ultra-think/SKILL.md` only for one consequential evidenced trade-off. If the
76
+ whole path is unclear, recommend Research instead of manufacturing tasks.
89
77
 
90
- When reconciliation proves the request is a directly executable one-slice correction,
91
- follow `../ultra-tdd/SKILL.md` at the confirmed public seam instead of manufacturing a
92
- task graph merely to satisfy ceremony.
78
+ Record `## Research Disposition` exactly. `none` needs enough evidence to plan;
79
+ `bounded` or `required` names one question, selected lenses, and exit evidence. After
80
+ Research, reconcile outputs here; an unverified path or bare claim is not evidence.
93
81
 
94
- Output is `.ultra/changes/active/<id>/intent.md`, the specification patches
95
- reconciliation justified, possibly a `.ultra/decisions/<id>.md`, and any
96
- vocabulary update. Recommend `ultra-research` for a real evidence gap or
97
- `ultra-plan` once the contract is evidenced enough; do not invoke either.
82
+ A quick active Change still goes through one-task `ultra-plan`; once durable intent
83
+ exists, that minimal task is what binds development, evidence, audit, and delivery to
84
+ the stable `change_id`.
85
+
86
+ Output active `intent.md` under a stable id, justified specification patches, qualifying
87
+ decision or vocabulary updates. For an evidence gap recommend `ultra-research`; when
88
+ evidenced recommend `ultra-plan`. Invoke neither.
98
89
 
99
90
  ## Abandoning a Change
100
91
 
101
- A Change that turns out to be the wrong thing to build exits by
102
- `git mv .ultra/changes/active/<id> .ultra/changes/abandoned/<id>`, plus one line in
103
- its `intent.md` saying why. Completed tasks keep their evidence; the work is
104
- unlinked from the frontier, not deleted. This is the owner's call and a cheap one —
105
- a Change kept alive to avoid admitting it was wrong poisons every later
106
- reconciliation, which then measures the code against promises nobody intends to keep.
92
+ Append the exact `## Abandonment` closure from `references/change-contract.md`, then
93
+ `git mv .ultra/changes/active/<id> .ultra/changes/abandoned/<id>`. Keep completed-task
94
+ evidence. Future Change and Status consume this history; it is neither current intent
95
+ nor an orphan. Abandonment is the owner's call.
107
96
 
108
97
  ## When the owner decides
109
98