ultra-builder-pro-cli 0.20.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ultra-template/docs/research/README.md +26 -5
- package/.ultra-template/specs/discovery.md +1 -1
- package/.ultra-template/tasks/tasks.json +1 -1
- package/CHANGELOG.md +66 -0
- package/README.md +54 -24
- package/adapters/_shared/codex-assets.cjs +69 -11
- package/adapters/_shared/interaction-contract.cjs +36 -3
- package/adapters/_shared/runtime-assets.cjs +41 -1
- package/adapters/claude.js +7 -5
- package/adapters/codex.js +1 -1
- package/adapters/kimi.js +2 -8
- package/adapters/opencode.js +30 -28
- package/bin/orchestrator.js +64 -24
- package/docs/AGENT-CONTEXT.md +74 -43
- package/docs/ARCHITECTURE.md +63 -31
- package/docs/ARTIFACT-AUTHORITY.md +234 -0
- package/docs/DECISIONS.md +10 -4
- package/docs/LEGACY-CLI-CROSSWALK.md +6 -4
- package/docs/PLUGIN-ISOLATION-CONTRACT.md +4 -3
- package/docs/ROADMAP.md +19 -5
- package/docs/RUNTIME-COMPAT-MATRIX.md +24 -13
- package/docs/STATE-DB-ACCESS-POLICY.md +11 -9
- package/docs/WORKFLOW-LIFECYCLE.md +70 -39
- package/hooks/README.md +6 -5
- package/hooks/active_task_context.py +97 -12
- package/hooks/context_spine.py +16 -4
- package/hooks/health_check.py +5 -4
- package/hooks/pre_stop_check.py +5 -2
- package/hooks/runtime_paths.py +396 -0
- package/hooks/subagent_tracker.py +5 -2
- package/hooks/workflow_checkpoint.py +16 -3
- package/hooks/workflow_context.py +11 -3
- package/hooks/workflow_resume.py +7 -4
- package/mcp-server/breadcrumb.cjs +20 -2
- package/mcp-server/lib/archive-journal.cjs +1026 -111
- package/mcp-server/lib/archive-mutation-worker.py +365 -0
- package/mcp-server/lib/artifact-registry.cjs +1126 -0
- package/mcp-server/lib/baseline-workflow.cjs +9 -4
- package/mcp-server/lib/change-packet.cjs +818 -0
- package/mcp-server/lib/change-workflow.cjs +932 -176
- package/mcp-server/lib/context-paths.cjs +111 -0
- package/mcp-server/lib/context-spine.cjs +511 -45
- package/mcp-server/lib/decision-dialogue.cjs +345 -3
- package/mcp-server/lib/delivery-transaction.cjs +471 -0
- package/mcp-server/lib/doctor-backup-worker.cjs +328 -0
- package/mcp-server/lib/doctor.cjs +373 -11
- package/mcp-server/lib/git-bootstrap.cjs +459 -47
- package/mcp-server/lib/init-project.cjs +190 -95
- package/mcp-server/lib/plan-publication-worker.cjs +830 -0
- package/mcp-server/lib/plan-store.cjs +700 -5
- package/mcp-server/lib/project-breadcrumb.cjs +23 -4
- package/mcp-server/lib/projector.cjs +174 -40
- package/mcp-server/lib/runtime-paths.cjs +1687 -0
- package/mcp-server/lib/safe-project-file.cjs +385 -0
- package/mcp-server/lib/spec-learning.cjs +28 -12
- package/mcp-server/lib/state-db.cjs +263 -9
- package/mcp-server/lib/state-ops.cjs +248 -49
- package/mcp-server/lib/telemetry.cjs +12 -3
- package/mcp-server/lib/workflow-state.cjs +610 -58
- package/mcp-server/server.cjs +278 -33
- package/orchestrator/daemon.cjs +2 -10
- package/orchestrator/parallel-orchestrator.cjs +314 -50
- package/orchestrator/planner/plan-builder.cjs +1 -1
- package/orchestrator/recovery.cjs +125 -7
- package/orchestrator/session-close-journal-worker.cjs +5 -0
- package/orchestrator/session-close-journal.cjs +1014 -0
- package/orchestrator/session-runner.cjs +679 -69
- package/orchestrator/worktree-manager.cjs +186 -35
- package/package.json +2 -3
- package/skills/cc-collab/SKILL.md +4 -1
- package/skills/codex-collab/SKILL.md +5 -2
- package/skills/ultra-change/SKILL.md +26 -8
- package/skills/ultra-deliver/SKILL.md +23 -11
- package/skills/ultra-dev/SKILL.md +33 -6
- package/skills/ultra-doctor/SKILL.md +6 -2
- package/skills/ultra-init/SKILL.md +4 -2
- package/skills/ultra-plan/SKILL.md +49 -16
- package/skills/ultra-research/SKILL.md +30 -27
- package/skills/ultra-review/SKILL.md +9 -5
- package/skills/ultra-status/SKILL.md +9 -4
- package/skills/ultra-test/SKILL.md +10 -5
- package/skills/ultra-think/SKILL.md +6 -2
- package/skills/ultra-think/references/decision-dialogue.md +17 -6
- package/skills/ultra-verify/SKILL.md +4 -1
- package/spec/cli-protocol.md +18 -7
- package/spec/mcp-tools.yaml +502 -44
- package/spec/schemas/change-delta.v1.schema.json +153 -0
- package/spec/schemas/documentation-reconciliation.v1.schema.json +106 -0
- package/spec/schemas/mcp-tools.schema.json +1 -1
- package/spec/schemas/state-db.sql +50 -13
- package/spec/schemas/tasks.v4.5.schema.json +1 -1
- package/ultra-tools/cli.cjs +3 -2
- package/ultra-tools/commands/db.cjs +76 -25
- package/ultra-tools/commands/migrate.cjs +995 -80
- package/ultra-tools/commands/session.cjs +34 -8
- package/ultra-tools/commands/status.cjs +32 -6
- package/ultra-tools/commands/system.cjs +129 -22
- package/commands/learn.md +0 -10
- package/orchestrator/skill-miner.cjs +0 -133
- package/output-styles/coding-vibes.md +0 -67
- package/output-styles/structural-thinking.md +0 -61
- package/skills/learn/SKILL.md +0 -58
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Phase 8B.3 — N-concurrent git worktree registry.
|
|
4
4
|
//
|
|
5
5
|
// Wraps session-runner's single-session gitWorktreeAdd/Remove with:
|
|
6
|
-
// • allocate({repoRoot, sid, baseRef}) — create .ultra/worktrees/<sid>
|
|
6
|
+
// • allocate({repoRoot, sid, baseRef}) — create .ultra/.runtime/worktrees/<sid>
|
|
7
7
|
// • release({repoRoot, worktree_path}) — remove one
|
|
8
8
|
// • listActive(repoRoot) — scan git + filter our domain
|
|
9
9
|
// • releaseAll(repoRoot) — batch cleanup (crash recovery)
|
|
@@ -16,27 +16,91 @@
|
|
|
16
16
|
const fs = require('node:fs');
|
|
17
17
|
const path = require('node:path');
|
|
18
18
|
const { execFileSync } = require('node:child_process');
|
|
19
|
+
const Database = require('better-sqlite3');
|
|
19
20
|
|
|
20
|
-
const
|
|
21
|
+
const runtimePaths = require('../mcp-server/lib/runtime-paths.cjs');
|
|
22
|
+
const gitBootstrap = require('../mcp-server/lib/git-bootstrap.cjs');
|
|
23
|
+
const { SessionRunnerError, _internal } = require('./session-runner.cjs');
|
|
21
24
|
|
|
22
|
-
const WORKTREE_DOMAIN = path.join(
|
|
25
|
+
const WORKTREE_DOMAIN = path.join(runtimePaths.RUNTIME_RELATIVE_DIR, 'worktrees');
|
|
23
26
|
|
|
24
27
|
function worktreePath(repoRoot, sid) {
|
|
25
|
-
|
|
28
|
+
_internal.assertSessionId(sid);
|
|
29
|
+
return _internal.assertManagedWorktreePath(
|
|
30
|
+
repoRoot,
|
|
31
|
+
path.join(repoRoot, WORKTREE_DOMAIN, sid),
|
|
32
|
+
{ sid },
|
|
33
|
+
);
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
function allocate({ repoRoot, sid, baseRef = 'HEAD' }) {
|
|
29
37
|
if (!repoRoot) throw new Error('allocate: repoRoot required');
|
|
30
38
|
if (!sid) throw new Error('allocate: sid required');
|
|
39
|
+
const authority = runtimePaths.ensureRuntimeState(repoRoot, {
|
|
40
|
+
admitStorageBoundary: () => gitBootstrap.ensureExistingProjectStorageBoundary(repoRoot),
|
|
41
|
+
});
|
|
31
42
|
const wt = worktreePath(repoRoot, sid);
|
|
32
43
|
_internal.gitWorktreeAdd(repoRoot, wt, baseRef); // throws WORKTREE_FAILED
|
|
33
|
-
|
|
44
|
+
try {
|
|
45
|
+
_internal.linkAuthorityIntoWorktree(repoRoot, wt, { authority });
|
|
46
|
+
return { worktree_path: wt, authority_db_path: authority.stateDbPath };
|
|
47
|
+
} catch (error) {
|
|
48
|
+
try { fs.rmSync(path.join(wt, '.ultra', '.runtime'), { force: true }); }
|
|
49
|
+
catch { /* best effort */ }
|
|
50
|
+
try { _internal.gitWorktreeRemove(repoRoot, wt); }
|
|
51
|
+
catch { /* original authority error is more actionable */ }
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
34
54
|
}
|
|
35
55
|
|
|
36
|
-
function
|
|
56
|
+
function sessionRemovalBlocker(repoRoot, sid, worktreePath) {
|
|
57
|
+
const dbPath = runtimePaths.pathsFor(repoRoot).stateDbPath;
|
|
58
|
+
if (!fs.existsSync(dbPath)) return null;
|
|
59
|
+
const db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
60
|
+
try {
|
|
61
|
+
const rows = db.prepare(
|
|
62
|
+
'SELECT sid, status, worktree_path FROM sessions WHERE sid = ?',
|
|
63
|
+
).all(sid);
|
|
64
|
+
for (const row of rows) {
|
|
65
|
+
let recorded;
|
|
66
|
+
let requested;
|
|
67
|
+
try { recorded = fs.realpathSync(row.worktree_path); }
|
|
68
|
+
catch { recorded = path.resolve(row.worktree_path); }
|
|
69
|
+
try { requested = fs.realpathSync(worktreePath); }
|
|
70
|
+
catch { requested = path.resolve(worktreePath); }
|
|
71
|
+
if (recorded !== requested) {
|
|
72
|
+
return `session ${sid} is bound to a different worktree`;
|
|
73
|
+
}
|
|
74
|
+
if (!['completed', 'crashed'].includes(row.status)) {
|
|
75
|
+
return `session ${sid} is nonterminal (${row.status})`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
} finally {
|
|
80
|
+
db.close();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function release({ repoRoot, worktree_path, sid = null }) {
|
|
37
85
|
if (!repoRoot) throw new Error('release: repoRoot required');
|
|
38
86
|
if (!worktree_path) throw new Error('release: worktree_path required');
|
|
39
|
-
|
|
87
|
+
const expectedSid = sid === null ? path.basename(worktree_path) : sid;
|
|
88
|
+
_internal.assertSessionId(expectedSid);
|
|
89
|
+
const managedPath = _internal.assertManagedWorktreePath(
|
|
90
|
+
repoRoot, worktree_path, { sid: expectedSid },
|
|
91
|
+
);
|
|
92
|
+
const sessionBlocker = sessionRemovalBlocker(
|
|
93
|
+
repoRoot, expectedSid, managedPath,
|
|
94
|
+
);
|
|
95
|
+
const integrationBlocker = _internal.worktreeRemovalBlocker(repoRoot, managedPath);
|
|
96
|
+
const blocker = sessionBlocker || integrationBlocker;
|
|
97
|
+
if (blocker) {
|
|
98
|
+
throw new SessionRunnerError(
|
|
99
|
+
'WORKTREE_NOT_INTEGRATED',
|
|
100
|
+
`refusing to remove ${managedPath}: ${blocker}`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
_internal.gitWorktreeRemove(repoRoot, managedPath);
|
|
40
104
|
}
|
|
41
105
|
|
|
42
106
|
function parsePorcelain(text) {
|
|
@@ -62,63 +126,150 @@ function parsePorcelain(text) {
|
|
|
62
126
|
return entries;
|
|
63
127
|
}
|
|
64
128
|
|
|
65
|
-
function
|
|
129
|
+
function gitDiscoveryError(message, cause) {
|
|
130
|
+
return new SessionRunnerError(
|
|
131
|
+
'WORKTREE_DISCOVERY_FAILED',
|
|
132
|
+
`cannot inspect Git worktrees safely: ${message}`,
|
|
133
|
+
{ cause },
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function hasGitMetadata(repoRoot) {
|
|
138
|
+
let current = path.resolve(repoRoot);
|
|
139
|
+
while (true) {
|
|
140
|
+
if (fs.lstatSync(path.join(current, '.git'), { throwIfNoEntry: false })) return true;
|
|
141
|
+
const parent = path.dirname(current);
|
|
142
|
+
if (parent === current) return false;
|
|
143
|
+
current = parent;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function runGitText(repoRoot, args, execGit) {
|
|
148
|
+
const value = execGit('git', args, {
|
|
149
|
+
cwd: repoRoot, stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf8',
|
|
150
|
+
});
|
|
151
|
+
if (typeof value !== 'string' && !Buffer.isBuffer(value)) {
|
|
152
|
+
throw gitDiscoveryError(`Git returned no output for ${args.join(' ')}`);
|
|
153
|
+
}
|
|
154
|
+
return String(value);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function listActive(repoRoot, { execGit = execFileSync } = {}) {
|
|
158
|
+
const metadataPresent = hasGitMetadata(repoRoot);
|
|
159
|
+
let inside;
|
|
160
|
+
try {
|
|
161
|
+
inside = runGitText(repoRoot, ['rev-parse', '--is-inside-work-tree'], execGit).trim();
|
|
162
|
+
} catch (error) {
|
|
163
|
+
const detail = String(error?.stderr || error?.message || error);
|
|
164
|
+
if (!metadataPresent && /not a git repository/i.test(detail)) return [];
|
|
165
|
+
if (error instanceof SessionRunnerError) throw error;
|
|
166
|
+
throw gitDiscoveryError(detail.trim(), error);
|
|
167
|
+
}
|
|
168
|
+
if (inside !== 'true') {
|
|
169
|
+
if (!metadataPresent && inside === 'false') return [];
|
|
170
|
+
throw gitDiscoveryError(`unexpected repository probe result: ${inside || '(empty)'}`);
|
|
171
|
+
}
|
|
172
|
+
|
|
66
173
|
let out;
|
|
67
174
|
try {
|
|
68
|
-
out =
|
|
69
|
-
cwd: repoRoot, stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf8',
|
|
70
|
-
});
|
|
175
|
+
out = runGitText(repoRoot, ['worktree', 'list', '--porcelain'], execGit);
|
|
71
176
|
} catch (err) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
process.stderr.write(`worktree-manager: listActive git call failed: ${err.message}\n`);
|
|
75
|
-
return [];
|
|
177
|
+
if (err instanceof SessionRunnerError) throw err;
|
|
178
|
+
throw gitDiscoveryError(String(err?.stderr || err?.message || err).trim(), err);
|
|
76
179
|
}
|
|
77
|
-
const rawDomainRoot =
|
|
180
|
+
const rawDomainRoot = _internal.assertManagedWorktreeRoot(repoRoot);
|
|
78
181
|
// On macOS tmpdir is a symlink (/var → /private/var); git returns realpath.
|
|
79
182
|
// Canonicalize both sides so prefix matching is robust.
|
|
80
183
|
const domainRoot = (fs.existsSync(rawDomainRoot)
|
|
81
184
|
? fs.realpathSync(rawDomainRoot)
|
|
82
185
|
: rawDomainRoot) + path.sep;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
186
|
+
const active = [];
|
|
187
|
+
for (const entry of parsePorcelain(out)) {
|
|
188
|
+
if (!entry.worktree) continue;
|
|
189
|
+
const physical = fs.existsSync(entry.worktree)
|
|
190
|
+
? fs.realpathSync(entry.worktree)
|
|
191
|
+
: path.resolve(entry.worktree);
|
|
192
|
+
if (!(physical + path.sep).startsWith(domainRoot)) continue;
|
|
193
|
+
const sid = path.basename(entry.worktree);
|
|
194
|
+
const canonical = _internal.assertManagedWorktreePath(
|
|
195
|
+
repoRoot, entry.worktree, { sid },
|
|
196
|
+
);
|
|
197
|
+
active.push({
|
|
198
|
+
sid,
|
|
199
|
+
worktree_path: canonical,
|
|
200
|
+
head: entry.head || null,
|
|
201
|
+
branch: entry.branch || null,
|
|
202
|
+
detached: !!entry.detached,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return active;
|
|
96
206
|
}
|
|
97
207
|
|
|
98
|
-
function releaseAll(repoRoot) {
|
|
99
|
-
const active = listActive(repoRoot);
|
|
208
|
+
function releaseAll(repoRoot, options = {}) {
|
|
209
|
+
const active = listActive(repoRoot, options);
|
|
210
|
+
const releaseWorktree = options.releaseWorktree || release;
|
|
100
211
|
let cleaned = 0;
|
|
212
|
+
const protectedSids = new Set();
|
|
213
|
+
const preserved = [];
|
|
214
|
+
const quarantined = [];
|
|
101
215
|
for (const entry of active) {
|
|
102
216
|
try {
|
|
103
|
-
|
|
217
|
+
releaseWorktree({
|
|
218
|
+
repoRoot,
|
|
219
|
+
worktree_path: entry.worktree_path,
|
|
220
|
+
sid: entry.sid,
|
|
221
|
+
});
|
|
104
222
|
cleaned += 1;
|
|
105
223
|
} catch (err) {
|
|
224
|
+
protectedSids.add(entry.sid);
|
|
225
|
+
preserved.push({
|
|
226
|
+
sid: entry.sid,
|
|
227
|
+
worktree_path: entry.worktree_path,
|
|
228
|
+
reason: err.message,
|
|
229
|
+
});
|
|
106
230
|
// Best-effort: one bad worktree shouldn't stop the sweep.
|
|
107
231
|
process.stderr.write(`worktree-manager: release(${entry.sid}) failed: ${err.message}\n`);
|
|
108
232
|
}
|
|
109
233
|
}
|
|
110
|
-
//
|
|
234
|
+
// Filesystem entries Git no longer owns are recovery evidence, not trash.
|
|
235
|
+
// Move real managed children atomically into quarantine and report the path.
|
|
111
236
|
const domainRoot = path.join(repoRoot, WORKTREE_DOMAIN);
|
|
112
237
|
if (fs.existsSync(domainRoot)) {
|
|
113
238
|
for (const name of fs.readdirSync(domainRoot)) {
|
|
114
239
|
const full = path.join(domainRoot, name);
|
|
115
|
-
try {
|
|
240
|
+
try {
|
|
241
|
+
if (protectedSids.has(name)) continue;
|
|
242
|
+
_internal.assertSessionId(name);
|
|
243
|
+
const managedPath = _internal.assertManagedWorktreePath(
|
|
244
|
+
repoRoot, full, { sid: name },
|
|
245
|
+
);
|
|
246
|
+
const recoveryRoot = path.join(
|
|
247
|
+
runtimePaths.pathsFor(repoRoot).runtimeDir,
|
|
248
|
+
'recovery',
|
|
249
|
+
'worktrees',
|
|
250
|
+
);
|
|
251
|
+
fs.mkdirSync(recoveryRoot, { recursive: true });
|
|
252
|
+
const token = new Date().toISOString().replace(/[:.]/g, '-');
|
|
253
|
+
let recoveryPath = path.join(recoveryRoot, `${token}-${name}`);
|
|
254
|
+
let attempt = 0;
|
|
255
|
+
while (fs.lstatSync(recoveryPath, { throwIfNoEntry: false })) {
|
|
256
|
+
attempt += 1;
|
|
257
|
+
recoveryPath = path.join(recoveryRoot, `${token}-${name}-${attempt}`);
|
|
258
|
+
}
|
|
259
|
+
fs.renameSync(managedPath, recoveryPath);
|
|
260
|
+
quarantined.push({
|
|
261
|
+
sid: name,
|
|
262
|
+
source_path: managedPath,
|
|
263
|
+
recovery_path: recoveryPath,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
116
266
|
catch (err) {
|
|
267
|
+
preserved.push({ sid: name, worktree_path: full, reason: err.message });
|
|
117
268
|
process.stderr.write(`worktree-manager: orphan sweep failed for ${full}: ${err.message}\n`);
|
|
118
269
|
}
|
|
119
270
|
}
|
|
120
271
|
}
|
|
121
|
-
return { cleaned };
|
|
272
|
+
return { cleaned, preserved, quarantined };
|
|
122
273
|
}
|
|
123
274
|
|
|
124
275
|
module.exports = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra-builder-pro-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.1",
|
|
4
4
|
"description": "Explicitly invoked Ultra Builder Pro workflows for Claude Code, OpenCode, Codex CLI, and Kimi Code, with project-local MCP authority and lifecycle recovery.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ultra-builder-pro-cli": "bin/install.js",
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
"orchestrator",
|
|
17
17
|
"commands",
|
|
18
18
|
"agents",
|
|
19
|
-
"skills/learn",
|
|
20
19
|
"skills/ultra-init",
|
|
21
20
|
"skills/ultra-research",
|
|
22
21
|
"skills/ultra-plan",
|
|
@@ -38,7 +37,6 @@
|
|
|
38
37
|
"hooks/*.py",
|
|
39
38
|
"hooks/adapters/*.py",
|
|
40
39
|
"hooks/README.md",
|
|
41
|
-
"output-styles",
|
|
42
40
|
"spec/mcp-tools.yaml",
|
|
43
41
|
"spec/cli-protocol.md",
|
|
44
42
|
"spec/schemas",
|
|
@@ -48,6 +46,7 @@
|
|
|
48
46
|
".ultra-template",
|
|
49
47
|
"docs/ROADMAP.md",
|
|
50
48
|
"docs/ARCHITECTURE.md",
|
|
49
|
+
"docs/ARTIFACT-AUTHORITY.md",
|
|
51
50
|
"docs/WORKFLOW-LIFECYCLE.md",
|
|
52
51
|
"docs/LEGACY-CLI-CROSSWALK.md",
|
|
53
52
|
"docs/AGENT-CONTEXT.md",
|
|
@@ -27,10 +27,13 @@ claude --safe-mode -p "<bounded prompt>" \
|
|
|
27
27
|
--no-session-persistence
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
Store large output under `.ultra/collab/<session-id>/claude-output.md`. A missing CLI,
|
|
30
|
+
Store large output under `.ultra/.runtime/collab/<session-id>/claude-output.md`. A missing CLI,
|
|
31
31
|
failed authentication, timeout, or empty response degrades to host-only analysis and
|
|
32
32
|
never blocks the underlying task.
|
|
33
33
|
|
|
34
|
+
Treat `.ultra/.runtime/collab/` as working scratch, not Ultra authority. Promote only verified
|
|
35
|
+
conclusions into the invoking DB-bound workflow artifact or report.
|
|
36
|
+
|
|
34
37
|
## Synthesis
|
|
35
38
|
|
|
36
39
|
Verify consequential claims against the current checkout, runtime, tests, or primary
|
|
@@ -17,10 +17,10 @@ evidence, edits, verification, and the final answer.
|
|
|
17
17
|
|
|
18
18
|
## Invocation
|
|
19
19
|
|
|
20
|
-
Create a session directory under `.ultra/collab/`, then run in a read-only sandbox:
|
|
20
|
+
Create a session directory under `.ultra/.runtime/collab/`, then run in a read-only sandbox:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
SESSION_PATH=".ultra/collab/$(date +%Y%m%d-%H%M%S)-codex"
|
|
23
|
+
SESSION_PATH=".ultra/.runtime/collab/$(date +%Y%m%d-%H%M%S)-codex"
|
|
24
24
|
mkdir -p "${SESSION_PATH}"
|
|
25
25
|
codex exec -s read-only \
|
|
26
26
|
--ephemeral \
|
|
@@ -35,6 +35,9 @@ Do not enable write-capable automation or permission bypass. The isolation flags
|
|
|
35
35
|
the advisory run independent from the user's Codex runtime configuration and rules;
|
|
36
36
|
the normal Codex authentication store remains available.
|
|
37
37
|
|
|
38
|
+
Treat `.ultra/.runtime/collab/` as working scratch, not Ultra authority. Promote only verified
|
|
39
|
+
conclusions into the invoking DB-bound workflow artifact or report.
|
|
40
|
+
|
|
38
41
|
## Synthesis
|
|
39
42
|
|
|
40
43
|
Read output only after the process exits and the file is non-empty. Verify
|
|
@@ -13,8 +13,8 @@ Read `../ultra-think/references/decision-dialogue.md` before asking a material q
|
|
|
13
13
|
|
|
14
14
|
## Inspect and align
|
|
15
15
|
|
|
16
|
-
1. Read `system.doctor`, `baseline.get`, active changes,
|
|
17
|
-
`change.breadcrumb`.
|
|
16
|
+
1. Read `system.doctor`, `baseline.get`, active changes, breadcrumb `accepted_intent`,
|
|
17
|
+
decisions, and `change.breadcrumb`.
|
|
18
18
|
2. Resume an existing change that matches the request. Do not duplicate authority.
|
|
19
19
|
3. Ordinary work requires a healthy ready baseline. An incident may use only an
|
|
20
20
|
explicit `baseline_bypass` reason and approver; urgency is not approval.
|
|
@@ -34,6 +34,10 @@ together with the research disposition. A quick change may have no material risk
|
|
|
34
34
|
research obligation, or more than one task. MCP may reject a profile that contradicts
|
|
35
35
|
hard risk invariants; it does not choose a replacement.
|
|
36
36
|
|
|
37
|
+
After `change.create` or `change.update`, read back the complete Change Contract. When
|
|
38
|
+
that write applies a durable decision, complete the decision thread with the change
|
|
39
|
+
reference in `applied_refs`.
|
|
40
|
+
|
|
37
41
|
Ask only when a choice changes accepted product intent, scope, public behavior,
|
|
38
42
|
compatibility, security, material cost, external effects, or recovery. Use the host's
|
|
39
43
|
native question UI when available. Normalize clear choices already in the user's
|
|
@@ -55,9 +59,19 @@ Call `change.create`. It records and completes exactly:
|
|
|
55
59
|
3. `record-intent`
|
|
56
60
|
|
|
57
61
|
The returned change workflow must be `completed`; research, plan, context, dev, test,
|
|
58
|
-
review, and deliver remain independent capabilities.
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
review, and deliver remain independent capabilities. Keep every Change-owned semantic
|
|
63
|
+
artifact, finding, plan, context, test result, review result, documentation update,
|
|
64
|
+
and progress projection below `.ultra/changes/active/<id>/`. Incidents maintain the
|
|
65
|
+
structured diagnosis artifact there as well.
|
|
66
|
+
|
|
67
|
+
Before planning a standard or major change, write the accepted specification updates
|
|
68
|
+
to the Change overlay and call `change.delta` with exact baseline id, repository
|
|
69
|
+
revision, specification digests, decisions, non-goals, acceptance, documentation
|
|
70
|
+
impact, unknowns, and mutation before/after digests. If accepted behavior truly does
|
|
71
|
+
not change baseline semantics, record an empty typed delta with a specific
|
|
72
|
+
`no_semantic_change_reason`; do not manufacture a mutation. Read back the registered
|
|
73
|
+
delta and deterministic `progress.md`. This records proposed authority only and must
|
|
74
|
+
not edit baseline specifications.
|
|
61
75
|
|
|
62
76
|
Use `change.update` when accepted intent or evidence changes. Update the Change
|
|
63
77
|
Contract, classification, research disposition, and docs impact together when their
|
|
@@ -66,9 +80,11 @@ change must become stale and be regenerated; never keep old evidence green by pr
|
|
|
66
80
|
assertion.
|
|
67
81
|
|
|
68
82
|
If research is required, recommend `ultra-research` with the recorded disposition. If
|
|
69
|
-
the contract is sufficiently evidenced,
|
|
70
|
-
|
|
71
|
-
|
|
83
|
+
the contract is sufficiently evidenced, finish the typed delta and recommend
|
|
84
|
+
`ultra-plan`. Direct Build skips Research only; it never skips Plan, DB-backed task
|
|
85
|
+
contracts, or fresh task context. Return and wait for an explicit user invocation; do
|
|
86
|
+
not start another workflow. `change.context` is compiled only for an actual plan,
|
|
87
|
+
implementation, test, or review consumer.
|
|
72
88
|
|
|
73
89
|
Stable implementation discoveries use the approval-gated specification-learning
|
|
74
90
|
transitions. External memory and graph providers retain their own content; Ultra stores
|
|
@@ -79,3 +95,5 @@ and `allowed_transitions`. Recommend a semantic next action from those transitio
|
|
|
79
95
|
If current intent does not already select it, present the recommendation and credible
|
|
80
96
|
alternatives through the interaction protocol, then wait. MCP does not encode a
|
|
81
97
|
semantic next action.
|
|
98
|
+
|
|
99
|
+
Never invoke the recommended capability here; wait for an explicit user invocation.
|
|
@@ -10,8 +10,8 @@ push, tag, registry publication, deployment, or another external effect.
|
|
|
10
10
|
|
|
11
11
|
## Bind current evidence
|
|
12
12
|
|
|
13
|
-
1. Read doctor, baseline, change, breadcrumb
|
|
14
|
-
and current checkout.
|
|
13
|
+
1. Read doctor, baseline, change, breadcrumb `accepted_intent`, decisions, tasks, test,
|
|
14
|
+
review, learning, and current checkout.
|
|
15
15
|
2. Resume or start a deliver workflow bound to the change and baseline.
|
|
16
16
|
3. Require complete task evidence, a current test report, both review axes, current
|
|
17
17
|
context, and resolved material decisions. Record `bind-evidence`.
|
|
@@ -21,25 +21,35 @@ Evidence from another revision, task set, or change is invalid.
|
|
|
21
21
|
## Reconcile specifications
|
|
22
22
|
|
|
23
23
|
Resolve every specification-learning candidate. Apply approved learning to its target
|
|
24
|
-
|
|
24
|
+
inside the Change overlay; preserve rejection reasons. Read the current registered
|
|
25
|
+
`change.delta` and verify every baseline anchor, payload digest, acceptance reference,
|
|
26
|
+
and unknown.
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
Write documentation updates below
|
|
29
|
+
`.ultra/changes/active/<change-id>/documentation/`. Call
|
|
30
|
+
`change.documentation_reconcile` for every Change: bind the current delta id and
|
|
31
|
+
digest, exact before/after document digests, delta and acceptance references,
|
|
32
|
+
verification, and each verified consumer. When no documentation changes, record an
|
|
33
|
+
empty reconciliation with a specific `no_change_reason`. An unexplained orphan
|
|
34
|
+
document is blocking. Record `reconcile-specifications`.
|
|
30
35
|
|
|
31
36
|
Compile final convergence context and run the risk-selected candidate checks, install
|
|
32
37
|
or doctor smoke when this change modifies distributed assets, public-seam verification,
|
|
33
38
|
and recovery sanity. Record the immutable context under `verify-candidate`.
|
|
34
39
|
|
|
35
40
|
Call `change.converge`; MCP derives readiness from durable dev, test, review,
|
|
36
|
-
|
|
41
|
+
typed delta, documentation reconciliation, diagnosis, and current checkout evidence.
|
|
42
|
+
Record
|
|
37
43
|
`converge-authority` only when ready.
|
|
38
44
|
|
|
39
|
-
Call `change.archive` with the
|
|
40
|
-
|
|
45
|
+
Call `change.archive` with the summary. MCP preflights all target before states and
|
|
46
|
+
overlay digests, applies the complete packet atomically, refreshes baseline authority,
|
|
47
|
+
rebinds every registered artifact into the self-contained archive, and rolls back or
|
|
48
|
+
resumes from its transaction journal after interruption. A partial success is not
|
|
49
|
+
delivery. Verify the refreshed baseline and archived packet, then record
|
|
50
|
+
`archive-change`.
|
|
41
51
|
|
|
42
|
-
Write
|
|
52
|
+
Write `<archived-change-root>/delivery/<workflow-id>/report.json` with
|
|
43
53
|
`ultra-delivery-report-v1`: archived change, baseline, HEAD, worktree and context
|
|
44
54
|
digests, local checks, rollback notes, and timestamp. The report must not contain a
|
|
45
55
|
release decision. Record it under `verify-delivery` and complete the workflow.
|
|
@@ -54,3 +64,5 @@ state.
|
|
|
54
64
|
|
|
55
65
|
Return archive and baseline state, evidence digests, recovery notes, residual risks,
|
|
56
66
|
and allowed transitions.
|
|
67
|
+
|
|
68
|
+
Never invoke the recommended capability here; wait for an explicit user invocation.
|
|
@@ -10,14 +10,23 @@ fresh context contract, session lease, evidence references, and recovery.
|
|
|
10
10
|
|
|
11
11
|
## Bind and resume
|
|
12
12
|
|
|
13
|
-
1. Read doctor, breadcrumb
|
|
14
|
-
sessions, HEAD, and worktree.
|
|
13
|
+
1. Read doctor, breadcrumb `accepted_intent`, active decisions, task contract,
|
|
14
|
+
dependencies, dev runs, sessions, HEAD, and worktree.
|
|
15
15
|
2. Resume the matching dev run or start one with `change_id` and `task_id`.
|
|
16
16
|
3. Record `bind-task` with current authority and dependency evidence.
|
|
17
|
-
4. Compile `change.context`
|
|
18
|
-
command, and refs
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
4. Compile `change.context` with `role: implement` and `gate: implementation`. The
|
|
18
|
+
public seam, verification command, and context refs come from the DB-backed task
|
|
19
|
+
contract; update that contract before compilation instead of overriding it in the
|
|
20
|
+
call. Persist any changed external-provider metadata with `change.update` first.
|
|
21
|
+
Context compilation itself is read-only with respect to Change and provider
|
|
22
|
+
authority.
|
|
23
|
+
5. Confirm the manifest contains the selected task, its direct dependencies, direct
|
|
24
|
+
dependents needed for integration, and relevant integration checkpoints—not the
|
|
25
|
+
entire task graph. Referenced file bodies stay lazy. The token estimate includes
|
|
26
|
+
inline Change/task authority as well as file estimates; budget overflow is
|
|
27
|
+
advisory, while a missing or stale required reference is blocking. Record the
|
|
28
|
+
immutable manifest as `compile-context`.
|
|
29
|
+
6. Reuse an existing valid session. Otherwise pass admission and call `session.spawn`.
|
|
21
30
|
Work only in the returned worktree and preserve unrelated changes.
|
|
22
31
|
|
|
23
32
|
Do not spawn recursively from a parent-owned worker session. Process exit is transport
|
|
@@ -41,6 +50,18 @@ evidence, never task completion.
|
|
|
41
50
|
6. Create the authorized local task commit. Do not push, publish, tag, or deploy unless
|
|
42
51
|
the user separately authorized that external effect.
|
|
43
52
|
|
|
53
|
+
Treat the compiled task-context contract as the handoff boundary: purpose, why,
|
|
54
|
+
constraints, non-goals, target seams/files, pattern refs, acceptance, documentation
|
|
55
|
+
impact, recovery, and definition of drift. If accepted intent, the task contract, or a
|
|
56
|
+
digest-bound reference changes, update the owning authority and recompile rather than
|
|
57
|
+
continuing from a stale packet.
|
|
58
|
+
|
|
59
|
+
Keep implementation findings and documentation candidates inside the owning Change
|
|
60
|
+
root. When code changes invalidate or extend maintained documentation, update the
|
|
61
|
+
Change documentation overlay and its evidence rather than editing accepted baseline
|
|
62
|
+
specifications. Hooks may remind the host to reconcile documentation; they must not
|
|
63
|
+
block ordinary development or choose the semantic update.
|
|
64
|
+
|
|
44
65
|
Task-level tests and review belong to this inner loop. They do not replace aggregate
|
|
45
66
|
change testing or review when multiple slices, integrations, or broader risks require
|
|
46
67
|
those capabilities.
|
|
@@ -51,6 +72,10 @@ In direct mode, integrate the task commit through the repository's accepted path
|
|
|
51
72
|
verify ancestry and the public seam, close the session, update the task to `completed`,
|
|
52
73
|
record `record-completion`, and complete the dev workflow.
|
|
53
74
|
|
|
75
|
+
Change convergence revalidates the exact latest
|
|
76
|
+
`change_id + task_id + implement + implementation` snapshot for every executable
|
|
77
|
+
task. A newer review, test, or plan packet cannot substitute for it.
|
|
78
|
+
|
|
54
79
|
In a parent-supervised worker, record completion evidence and exit without closing the
|
|
55
80
|
parent-owned lease. The primary host verifies the exact session commit, performs any
|
|
56
81
|
integration, refreshes review if the reviewed checkout changed, settles the lease, and
|
|
@@ -62,3 +87,5 @@ worktree and evidence, and resume the same run later.
|
|
|
62
87
|
|
|
63
88
|
Return outcome, changed paths, public seam, exact checks, review axes, commit and
|
|
64
89
|
session state, residual risk, and allowed transitions.
|
|
90
|
+
|
|
91
|
+
Never invoke the recommended capability here; wait for an explicit user invocation.
|
|
@@ -13,7 +13,9 @@ work complete.
|
|
|
13
13
|
|
|
14
14
|
Run `system.doctor` without repair and inspect:
|
|
15
15
|
|
|
16
|
-
- SQLite integrity, schema
|
|
16
|
+
- SQLite integrity, schema 20 migration, required tables, and backups;
|
|
17
|
+
- artifact registration, ownership, digest freshness, dependency edges, consumers,
|
|
18
|
+
and orphan or duplicate authority;
|
|
17
19
|
- baseline and research provenance, gaps, digests, and Git/worktree drift;
|
|
18
20
|
- workflow status, obsolete-step migration, blockers, and output freshness;
|
|
19
21
|
- decisions and checkpoint artifact freshness;
|
|
@@ -30,7 +32,7 @@ by doctor.
|
|
|
30
32
|
With explicit repair authorization, `system.doctor` may:
|
|
31
33
|
|
|
32
34
|
- apply backup-first supported schema migrations;
|
|
33
|
-
- migrate
|
|
35
|
+
- migrate incompatible rigid workflows into recoverable adaptive state;
|
|
34
36
|
- requeue or regenerate projections from healthy DB authority;
|
|
35
37
|
- reconcile orphan sessions without deleting unrelated or dirty worktrees;
|
|
36
38
|
- resume supported archive journals;
|
|
@@ -48,3 +50,5 @@ entry points, MCP startup, and hook smoke tests as applicable.
|
|
|
48
50
|
|
|
49
51
|
Return health first, failed checks, mechanical repairs performed, preserved recovery
|
|
50
52
|
paths, unresolved owners, and allowed transitions plus any unique required transition.
|
|
53
|
+
|
|
54
|
+
Never invoke the recommended capability here; wait for an explicit user invocation.
|
|
@@ -13,7 +13,7 @@ the next semantic workflow.
|
|
|
13
13
|
|
|
14
14
|
1. Identify the repository root, existing `.ultra` state, Git state, meaningful source,
|
|
15
15
|
monorepo boundaries, and current owner request.
|
|
16
|
-
2. If `.ultra/state.db` exists, run `system.doctor` read-only and resume with
|
|
16
|
+
2. If `.ultra/.runtime/state.db` exists, run `system.doctor` read-only and resume with
|
|
17
17
|
`task.init_project` only when its report permits it.
|
|
18
18
|
3. Otherwise call `task.init_project` with `mode: "auto"`, the project name, and an
|
|
19
19
|
explicit scope only when the repository contains multiple plausible roots.
|
|
@@ -48,7 +48,7 @@ unresolved. Normalize clear intent already present in the request without asking
|
|
|
48
48
|
|
|
49
49
|
The operation must:
|
|
50
50
|
|
|
51
|
-
- create or migrate `.ultra/state.db` with a backup before schema migration;
|
|
51
|
+
- create or migrate `.ultra/.runtime/state.db` with a backup before schema migration;
|
|
52
52
|
- install only missing scaffold assets on resume;
|
|
53
53
|
- preserve existing artifacts and unrelated work;
|
|
54
54
|
- preserve an existing Git repository and HEAD;
|
|
@@ -81,3 +81,5 @@ Read the returned `allowed_transitions` and `required_transition`:
|
|
|
81
81
|
Report classification, scope, schema and backup result, Git state, init workflow id,
|
|
82
82
|
baseline state, and allowed transitions. Do not claim that a baseline is ready until a
|
|
83
83
|
separate research/adoption workflow has recorded and converged it.
|
|
84
|
+
|
|
85
|
+
Never invoke the recommended capability here; wait for an explicit user invocation.
|