Skip to content

Commit 2813619

Browse files
committed
feat: add Git team checkpoints for Ultra state
Cause: the tracked task projection mixed checkout-local SQLite state with team handoff state, creating baseline HEAD churn and unsafe cross-checkout synchronization. Scope: add the digest-chained baseline/Change/task ledger and MCP publish/import tools, move generated views below .ultra/.runtime, migrate matching legacy projections with backups, stabilize baseline freshness and completion commits, and align all four host adapters, Skills, schemas, templates, and documentation. Release version is 0.22.0. Verification: npm run verify:release; npm pack --dry-run --json; repeated daemon immediate-poll regression test. Residual risk: concurrent edits to the same durable record intentionally fail closed and require explicit reconciliation; imported ready baselines require local revalidation. Rollback: git revert this commit, reinstall the prior published version, and restore any legacy task projection from its managed exact-byte backup if migration had already run.
1 parent 07a2883 commit 2813619

76 files changed

Lines changed: 3895 additions & 538 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ templates/
9595
!/.ultra-template/reports/
9696
!/.ultra-template/reports/templates/
9797
!/.ultra-template/reports/templates/**
98+
!/.ultra-template/templates/
99+
!/.ultra-template/templates/**
98100

99101
# npm / build artifacts
100102
node_modules/

.ultra-template/tasks/contexts/TEMPLATE.md

Lines changed: 0 additions & 19 deletions
This file was deleted.

.ultra-template/tasks/tasks.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
{
2-
"schema_version": "4.5",
3-
"generated_at": "1970-01-01T00:00:00.000Z",
4-
"source": ".ultra/.runtime/state.db",
2+
"kind": "ultra-team-task-ledger",
3+
"schema_version": "1.0",
4+
"generation": 0,
5+
"parent_digest": null,
6+
"ancestors": [],
7+
"state_digest": "5bf27fb3627b711c97abf72f0aad150ba693d35bcebdd57c2d80e325f495de6d",
8+
"published_at": null,
9+
"reason": "scaffold",
10+
"baseline": null,
11+
"changes": [],
512
"tasks": []
613
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!-- Runtime task views are generated under .ultra/.runtime/projections/contexts/. -->
2+
3+
# Task Context Reference
4+
5+
Use this file only as a structure reference. Runtime task context views are generated
6+
from SQLite authority and must not be edited by hand. Stable specification learning
7+
must follow the Change workflow.
8+
9+
## Implementation Notes
10+
11+
- [Evidence-backed note with a source reference]
12+
13+
## Open Questions
14+
15+
- [Question, consequence, owner, and next evidence]
16+
17+
## Recovery Notes
18+
19+
- [Current safe resume point and any external prerequisite]

CHANGELOG.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.22.0] — 2026-07-30
11+
12+
### Added
13+
14+
- Added a versioned, digest-chained Git team checkpoint at
15+
`.ultra/tasks/tasks.json` for portable baseline, Change, task-contract,
16+
dependency, and durable task-status handoff.
17+
- Added `task.ledger_get`, `task.ledger_publish`, and `task.ledger_import` with
18+
per-record revisions, bounded ancestry, transactional fast-forward imports,
19+
and typed baseline, Change, task, deletion, and active-session conflicts.
20+
- Added exact-byte backup and deterministic upgrade of matching legacy v4.4
21+
and v4.5 task projections during project resume.
22+
23+
### Changed
24+
25+
- Moved generated task and context views under
26+
`.ultra/.runtime/projections/`; SQLite remains checkout-local operational
27+
authority while the Git checkpoint is the narrow team handoff.
28+
- Updated all public workflow Skills, project templates, hooks, adapters, and
29+
documentation to inspect and synchronize the team checkpoint without
30+
turning hooks or host adapters into semantic authorities.
31+
- Made imported ready baselines require checkout-local revalidation before
32+
they may publish a descendant checkpoint.
33+
34+
### Fixed
35+
36+
- Fixed tracked task projections creating a self-referential
37+
`BASELINE_HEAD_STALE` treadmill after every Ultra operation or metadata-only
38+
commit. Baseline freshness now uses scoped source content plus Git ancestry
39+
while continuing to detect specification and source drift.
40+
- Fixed task completion requiring a second bookkeeping commit. The completion
41+
SHA is now backfilled only into local SQLite and generated views after the
42+
single real completion commit.
43+
- Fixed resume, doctor, status, and four-host install paths disagreeing about
44+
legacy task projections, team checkpoints, generated views, and protected
45+
files.
46+
- Replaced the daemon's machine-speed-dependent 500ms release assertion with a
47+
bounded observable-session wait while preserving the immediate-poll
48+
behavior requirement.
49+
1050
## [0.21.1] — 2026-07-29
1151

1252
### Fixed

README.md

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ Ultra Builder Pro addresses those gaps with four ideas:
4343
2. **Low-load user alignment.** The agent investigates observable facts itself
4444
and asks the user only for material intent, scope, risk, or authorization
4545
decisions—normally one dependent decision at a time.
46-
3. **Durable project authority.** `.ultra/.runtime/state.db` records baselines, changes,
47-
decisions, workflows, tasks, evidence digests, sessions, incidents, and
48-
recovery state across hosts and sessions.
46+
3. **Durable project authority.** `.ultra/.runtime/state.db` records checkout-local
47+
lifecycle, decisions, workflows, evidence digests, sessions, incidents, and
48+
recovery state across host sessions. Tracked semantic artifacts plus the
49+
MCP-published `.ultra/tasks/tasks.json` checkpoint carry reviewed project intent
50+
across Git checkouts without committing SQLite, leases, or telemetry.
4951
4. **Convergent delivery.** Research, plans, implementation, tests, review, and
5052
specification updates must agree before a change is archived.
5153

@@ -69,10 +71,12 @@ flowchart TB
6971
end
7072
7173
SKILLS["Eleven explicit Ultra Skills<br/>init / research / think / change / plan / dev<br/>test / review / deliver / status / doctor"]
72-
MCP["Ultra MCP<br/>57 typed tools across nine families"]
74+
MCP["Ultra MCP<br/>60 typed tools across nine families"]
7375
DB[(".ultra/.runtime/state.db<br/>SQLite lifecycle and index authority")]
76+
LEDGER[".ultra/tasks/tasks.json<br/>Git team checkpoint for portable baseline, Change, and task state"]
77+
VIEWS[".ultra/.runtime/projections<br/>checkout-local generated views"]
7478
FILES["Digest-bound .ultra artifacts<br/>specification / research / change / plan / context<br/>test / review / delivery"]
75-
HOOKS["Lifecycle hooks<br/>health, breadcrumbs, recovery hints, and projection protection"]
79+
HOOKS["Lifecycle hooks<br/>health, breadcrumbs, recovery hints, and managed-file protection"]
7680
OPS["Operational tools<br/>ubp / ultra-tools / optional orchestrator"]
7781
EXTERNAL["External memory and graph providers"]
7882
@@ -83,6 +87,8 @@ flowchart TB
8387
MODEL -->|"explicit invocation"| SKILLS
8488
SKILLS -->|"typed operations"| MCP
8589
MCP <--> DB
90+
MCP -->|"publish / validate / import"| LEDGER
91+
MCP -->|"regenerate"| VIEWS
8692
MODEL -->|"writes semantic and evidence bodies"| FILES
8793
MCP <-->|"registers owner, digest, provenance, and freshness"| FILES
8894
HOOKS -->|"observes and records lifecycle events"| MCP
@@ -97,9 +103,9 @@ The responsibility split is deliberate:
97103
|---|---|
98104
| **User** | Product intent, semantic route selection, material scope and trade-offs, risk acceptance, destructive actions, publishing and deployment authorization |
99105
| **Host model** | Fact-finding, synthesis, research-coverage and route recommendations, reversible implementation decisions |
100-
| **Ultra MCP** | Durable state, evidence references, digests, freshness, locks, valid transitions and hard recovery |
106+
| **Ultra MCP** | Checkout-local state, evidence references, digests, freshness, locks, valid transitions, hard recovery, and Git checkpoint publish/import |
101107
| **Host adapter** | Native Skill discovery, user questions, tool invocation, installation, and runtime wiring |
102-
| **Hooks** | Fast lifecycle observation, current breadcrumb injection, and protection of generated projections |
108+
| **Hooks** | Fast lifecycle observation, current breadcrumb injection, and protection of MCP-owned checkpoint and generated projection paths |
103109

104110
The MCP does not replace the model's judgment. A hook does not decide product
105111
strategy. A prompt does not become durable authority merely because it appeared
@@ -298,8 +304,11 @@ that rationale is useful. MCP validates state, evidence, and transitions; it
298304
does not store or prove the preceding UI interaction.
299305

300306
Older projection-only Ultra projects are preserved and routed through a
301-
backup-first migration or rebaseline. Use `ultra-doctor` when initialization
302-
reports migration or authority damage; do not overwrite old state manually.
307+
backup-first migration or rebaseline. The first supported checkpoint publication
308+
replaces a v4.4/v4.5 task projection only when its ids and durable fields match
309+
SQLite, after copying its exact bytes to `.ultra/.runtime/backups/task-ledger/`.
310+
Use `ultra-doctor` when initialization reports migration, mismatch, or authority
311+
damage; do not overwrite old state manually.
303312

304313
### 3. Make daily changes
305314

@@ -418,6 +427,7 @@ health without selecting product intent.
418427
.runtime/ # local mutable state; ignored by Git
419428
state.db # lifecycle, index, transition, and freshness authority
420429
checkpoint.json # advisory recovery projection
430+
projections/ # generated local task and task-context views
421431
backups/ # verified migration and recovery snapshots
422432
collab/ # local collaboration scratch
423433
sessions/ # local leases and session runtime
@@ -442,17 +452,20 @@ health without selecting product intent.
442452
docs/research/ # baseline-only research evidence
443453
reports/templates/ # blank report schemas; never delivery evidence
444454
tasks/
445-
tasks.json # generated projection, never the authority
446-
contexts/ # bounded role/task context artifacts
455+
tasks.json # MCP-published Git team checkpoint; never hand-edited
456+
templates/
457+
task-context.md # authored template, not a generated task context
447458
```
448459

449460
Together, `.ultra/` is Ultra's project-local cross-session workflow memory. The
450461
host model writes semantic specifications and evidence through the active
451462
workflow. MCP records lifecycle state, references, digests, provenance, and
452463
accepted intent, then rejects stale or illegal transitions. The DB is the
453-
lifecycle and index authority; registered digest-bound files carry the semantic
454-
or evidence bodies that the DB references. Generated projections and working
455-
scratch are not authority.
464+
lifecycle and index authority for one checkout; registered digest-bound files carry
465+
the semantic or evidence bodies that the DB references. The Git checkpoint is a
466+
portable, digest-chained handoff of baseline, Change, and durable task records. It is
467+
not a second live session authority. Generated projections and working scratch are
468+
not authority.
456469

457470
Ultra does not store chain-of-thought, raw prompts, transcripts, general
458471
conversational or episodic memory, or code-graph payloads. External memory and
@@ -461,6 +474,29 @@ references to them as workflow context. Only `.ultra/.runtime/` is ignored by
461474
Git: semantic and evidence artifacts can travel with the repository, while
462475
SQLite, leases, telemetry, and recovery scratch remain checkout-local.
463476

477+
### Team checkpoint protocol
478+
479+
MCP publishes `.ultra/tasks/tasks.json` at durable boundaries: baseline convergence,
480+
Change creation or revision, accepted plan export, durable task-contract or status
481+
changes, task expansion or deletion, and Change convergence or archive. The file
482+
contains per-record revisions and digests plus checkpoint ancestry. It excludes
483+
`in_progress` ownership, session ids, leases, worktrees, telemetry, and
484+
`completion_commit`.
485+
486+
After a pull or on a fresh checkout, MCP validates and imports the checkpoint. Clean
487+
records fast-forward independently. A baseline imported as `ready` is downgraded to
488+
checkout-local revalidation until its scope, files, verification, and HEAD are proven
489+
again. Concurrent edits to the same baseline, Change, or task, a non-descendant
490+
checkpoint, or remote modification of an active local task fail with a typed conflict;
491+
Ultra never silently picks a side. Re-importing the same checkpoint is read-only, and
492+
an imported ready baseline cannot publish another checkpoint until local revalidation
493+
converges.
494+
495+
Baseline freshness does not use the checkpoint commit as a self-referential marker.
496+
It combines Git ancestry with a scoped content digest that excludes `.ultra/`.
497+
Consequently, a commit containing only Ultra metadata does not make the baseline stale,
498+
while a descendant commit that changes scoped application content does.
499+
464500
See [Artifact authority](./docs/ARTIFACT-AUTHORITY.md) for the promotion and
465501
evidence rules.
466502

@@ -514,8 +550,11 @@ host's existing model session.
514550
reinstall only the degraded host.
515551
- **Project state is unhealthy:** invoke `ultra-doctor` or run
516552
`ultra-tools system doctor`. Repairs and schema migrations are backup-first.
517-
- **A projection disagrees with MCP:** trust `.ultra/.runtime/state.db`; do not repair
518-
`tasks.json` or generated context Markdown by hand.
553+
- **The team checkpoint disagrees with local state:** run `ultra-status`, inspect the
554+
typed ledger condition, then use the recommended `task.ledger_import` or
555+
`task.ledger_publish` path. Never edit `.ultra/tasks/tasks.json` by hand.
556+
- **A generated view disagrees with MCP:** trust `.ultra/.runtime/state.db`; never edit
557+
`.ultra/.runtime/projections/` by hand.
519558
- **A workflow appears blocked:** use `ultra-status` to read the exact current
520559
workflow, blocker, owner decision, and mechanically valid transitions.
521560
- **Kimi reports a native-module ABI error:** ensure an external Node.js 22+

adapters/opencode.js

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,8 @@ import path from "node:path";
337337
import { execFileSync } from "node:child_process";
338338
import { fileURLToPath } from "node:url";
339339
340-
const TASKS_PROJECTION = ".ultra/tasks/tasks.json";
340+
const TEAM_TASK_LEDGER = ".ultra/tasks/tasks.json";
341+
const LIVE_TASK_PROJECTION = ".ultra/.runtime/projections/tasks.json";
341342
const NODE_BINARY = ${JSON.stringify(process.execPath)};
342343
const PLUGIN_DIR = path.dirname(fileURLToPath(import.meta.url));
343344
const BREADCRUMB_CLI = path.resolve(
@@ -382,20 +383,28 @@ function targetPaths(tool, args) {
382383
return [...new Set(paths)];
383384
}
384385
385-
function projectionRootForTarget(baseRoot, candidate) {
386+
function managedTaskRootForTarget(baseRoot, candidate) {
386387
const target = path.isAbsolute(candidate)
387388
? path.resolve(candidate)
388389
: path.resolve(baseRoot, candidate);
389-
if (path.basename(target) !== "tasks.json"
390-
|| path.basename(path.dirname(target)) !== "tasks"
391-
|| path.basename(path.dirname(path.dirname(target))) !== ".ultra") {
392-
return null;
390+
if (target === path.resolve(baseRoot, TEAM_TASK_LEDGER)
391+
|| target === path.resolve(baseRoot, LIVE_TASK_PROJECTION)) return baseRoot;
392+
if (path.basename(target) !== "tasks.json") return null;
393+
const parent = path.dirname(target);
394+
if (path.basename(parent) === "tasks"
395+
&& path.basename(path.dirname(parent)) === ".ultra") {
396+
return path.dirname(path.dirname(parent));
397+
}
398+
if (path.basename(parent) === "projections"
399+
&& path.basename(path.dirname(parent)) === ".runtime"
400+
&& path.basename(path.dirname(path.dirname(parent))) === ".ultra") {
401+
return path.dirname(path.dirname(path.dirname(parent)));
393402
}
394-
return path.dirname(path.dirname(path.dirname(target)));
403+
return null;
395404
}
396405
397-
function protectsTasksProjection(baseRoot, candidate) {
398-
const targetRoot = projectionRootForTarget(baseRoot, candidate);
406+
function protectsManagedTaskFile(baseRoot, candidate) {
407+
const targetRoot = managedTaskRootForTarget(baseRoot, candidate);
399408
if (!targetRoot) return false;
400409
return Boolean(readUltraContext(targetRoot));
401410
}
@@ -421,11 +430,13 @@ export const UltraBuilderProPlugin = async ({ directory, worktree }) => {
421430
const tool = String(input?.tool ?? "").toLowerCase();
422431
if (!["write", "edit", "apply_patch"].includes(tool)) return;
423432
if (targetPaths(tool, output?.args).some(
424-
(candidate) => protectsTasksProjection(root, candidate),
433+
(candidate) => protectsManagedTaskFile(root, candidate),
425434
)) {
426435
throw new Error(
427-
"Ultra Builder Pro refused a direct write to .ultra/tasks/tasks.json. " +
428-
".ultra/.runtime/state.db is authoritative; use MCP task tools and run ultra-doctor when state or projection health is degraded."
436+
"Ultra Builder Pro refused a direct write to an MCP-managed task file. " +
437+
".ultra/tasks/tasks.json is the MCP-published team checkpoint and " +
438+
".ultra/.runtime/projections/tasks.json is the checkout-local DB view. " +
439+
"Use the Ultra MCP task or task.ledger tools."
429440
);
430441
}
431442
},

adapters/tests/claude.test.cjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ test('Claude plugin collaboration workflows are safe native plugin assets', () =
107107
assert.match(review, /scripts\/review_wait\.py/);
108108
assert.doesNotMatch(plan, /LEGACY_STATE_MIGRATION_REQUIRED|v4\.4|v4\.5/);
109109
assert.match(plan, /Never read or\s+write .*tasks\.json/i);
110-
assert.match(status, /Never fall\s+back to generated task JSON/i);
110+
assert.match(
111+
status,
112+
/Never fall\s+back to the Git team checkpoint,\s+generated task\s+JSON/i,
113+
);
111114
assert.doesNotMatch(plan, /ultra-tools task create/);
112115

113116
for (const name of skillsForRuntime('claude')) {

adapters/tests/codex-hook.test.cjs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,7 @@ test('Codex hook adapter denies apply_patch writes to tasks.json after Ultra ini
129129
assert.equal(result.status, 0, result.stderr);
130130
const output = JSON.parse(result.stdout);
131131
assert.equal(output.hookSpecificOutput.permissionDecision, 'deny');
132-
assert.match(
133-
output.hookSpecificOutput.permissionDecisionReason,
134-
/\.ultra\/\.runtime\/state\.db/,
135-
);
132+
assert.match(output.hookSpecificOutput.permissionDecisionReason, /team checkpoint/);
136133
} finally {
137134
fs.rmSync(project, { recursive: true, force: true });
138135
}

adapters/tests/codex.test.cjs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,10 @@ test('every generated skill is Codex-valid, UI-visible, and free of Claude host
180180
const status = fs.readFileSync(path.join(layout.pluginRoot, 'skills', 'ultra-status', 'SKILL.md'), 'utf8');
181181
assert.doesNotMatch(plan, /LEGACY_STATE_MIGRATION_REQUIRED|v4\.4|v4\.5/);
182182
assert.match(plan, /Never read or\s+write .*tasks\.json/i);
183-
assert.match(status, /Never fall\s+back to generated task JSON/i);
183+
assert.match(
184+
status,
185+
/Never fall\s+back to the Git team checkpoint,\s+generated task\s+JSON/i,
186+
);
184187

185188
const coreWorkflowText = [
186189
...COMMANDS,
@@ -297,8 +300,8 @@ test('plugin declares current Codex hooks and a project-local Ultra MCP server',
297300
const upstreamSpec = yaml.load(fs.readFileSync(path.join(layout.pluginRoot, 'spec', 'upstream-mcp-tools.yaml'), 'utf8'));
298301
const capabilityMap = JSON.parse(fs.readFileSync(path.join(layout.pluginRoot, 'spec', 'codex-capability-map.json'), 'utf8'));
299302
const interaction = JSON.parse(fs.readFileSync(path.join(layout.pluginRoot, 'spec', 'interaction-contract.json'), 'utf8'));
300-
assert.equal(liveSpec.tools.length, 57);
301-
assert.equal(upstreamSpec.tools.length, 57);
303+
assert.equal(liveSpec.tools.length, 60);
304+
assert.equal(upstreamSpec.tools.length, 60);
302305
assert.deepEqual(upstreamSpec.tools.map((tool) => tool.name).sort(), liveSpec.tools.map((tool) => tool.name).sort());
303306
assert.deepEqual(capabilityMap.live_mcp_tools.sort(), liveSpec.tools.map((tool) => tool.name).sort());
304307
assert.equal(Object.keys(capabilityMap.codex_native_replacements).length, 9);

0 commit comments

Comments
 (0)