@brainervirus/workit-codex 8.25.0 → 8.26.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/.codex-plugin/plugin.json +1 -1
- package/dist/launch-mcp.js +149 -5
- package/dist/{workit-hook-7a6v1719.js → workit-hook-sza2zvq6.js} +5 -5
- package/dist/workit-hook.js +1 -1
- package/package.json +3 -3
- package/skills/workit-fanout/SKILL.md +4 -4
- package/skills/workit-fanout/references/orchestration.md +26 -17
- package/skills/workit-implement/SKILL.md +1 -1
- package/skills/workit-review/SKILL.md +2 -1
- package/skills/workit-ship/SKILL.md +1 -1
package/dist/launch-mcp.js
CHANGED
|
@@ -14864,6 +14864,7 @@ var workspaceConfigSchema = object({
|
|
|
14864
14864
|
trailers: boolean2().optional(),
|
|
14865
14865
|
liveSessionGuard: boolean2().optional(),
|
|
14866
14866
|
fanout: object({ tierModels: unknown().optional() }).passthrough().optional(),
|
|
14867
|
+
models: object({ roles: unknown().optional() }).passthrough().optional(),
|
|
14867
14868
|
autonomy: object(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
|
|
14868
14869
|
kind,
|
|
14869
14870
|
union([boolean2(), literal("verified")]).optional()
|
|
@@ -14890,7 +14891,10 @@ var workspaceConfigSchema = object({
|
|
|
14890
14891
|
});
|
|
14891
14892
|
}
|
|
14892
14893
|
});
|
|
14893
|
-
var workspacesFileSchema = object({
|
|
14894
|
+
var workspacesFileSchema = object({
|
|
14895
|
+
workspaces: array(workspaceConfigSchema).optional(),
|
|
14896
|
+
models: object({ roles: unknown().optional() }).passthrough().optional()
|
|
14897
|
+
}).passthrough().superRefine((file, context) => {
|
|
14894
14898
|
const names = new Set;
|
|
14895
14899
|
for (const [index, workspace] of (file.workspaces ?? []).entries()) {
|
|
14896
14900
|
if (names.has(workspace.name)) {
|
|
@@ -15180,6 +15184,34 @@ var resolveRuntimeReleaseTracks = (cwd) => {
|
|
|
15180
15184
|
const matched = matchRuntimeWorkspace(cwd);
|
|
15181
15185
|
return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
|
|
15182
15186
|
};
|
|
15187
|
+
var modelSources = (cwd, dir) => {
|
|
15188
|
+
const out = [];
|
|
15189
|
+
try {
|
|
15190
|
+
const matched = matchRuntimeWorkspace(cwd, dir);
|
|
15191
|
+
if (matched) {
|
|
15192
|
+
const enclosing = matched.matches.filter((entry) => entry !== matched.selected).toSorted((a, b) => globSpecificity(b.glob) - globSpecificity(a.glob));
|
|
15193
|
+
for (const entry of [matched.selected, ...enclosing])
|
|
15194
|
+
out.push({
|
|
15195
|
+
name: entry.name,
|
|
15196
|
+
global: false,
|
|
15197
|
+
models: entry.models,
|
|
15198
|
+
tierModels: entry.fanout?.tierModels
|
|
15199
|
+
});
|
|
15200
|
+
}
|
|
15201
|
+
} catch {}
|
|
15202
|
+
try {
|
|
15203
|
+
const document = JSON.parse(readFileSync2(path4.join(dir ?? configDir(), "workspaces.json"), "utf8"));
|
|
15204
|
+
if (document && typeof document === "object" && !Array.isArray(document))
|
|
15205
|
+
out.push({
|
|
15206
|
+
name: "global",
|
|
15207
|
+
global: true,
|
|
15208
|
+
models: document.models,
|
|
15209
|
+
tierModels: undefined
|
|
15210
|
+
});
|
|
15211
|
+
} catch {}
|
|
15212
|
+
return out;
|
|
15213
|
+
};
|
|
15214
|
+
var hostFamily = (host) => host.replace(/_(?:cli|desktop)$/u, "");
|
|
15183
15215
|
var TIER_KEYS = new Set(["mundane", "standard", "hard"]);
|
|
15184
15216
|
var TIER_HOSTS = new Set([
|
|
15185
15217
|
"claude_code",
|
|
@@ -28343,6 +28375,92 @@ var codexCapabilities = (host, availability = {}) => capabilitiesFor(codexDescri
|
|
|
28343
28375
|
if (false)
|
|
28344
28376
|
;
|
|
28345
28377
|
|
|
28378
|
+
// packages/workit-core/src/core/role-models.ts
|
|
28379
|
+
var MODEL_ROLES = [
|
|
28380
|
+
"decider",
|
|
28381
|
+
"implementer",
|
|
28382
|
+
"verifier",
|
|
28383
|
+
"reviewer",
|
|
28384
|
+
"explore",
|
|
28385
|
+
"babysit"
|
|
28386
|
+
];
|
|
28387
|
+
var MODEL_TIERS = ["mundane", "standard", "hard"];
|
|
28388
|
+
var HOST_KEYS = new Set([
|
|
28389
|
+
"claude_code",
|
|
28390
|
+
"opencode",
|
|
28391
|
+
"codex",
|
|
28392
|
+
"codex_cli",
|
|
28393
|
+
"codex_desktop",
|
|
28394
|
+
"cursor",
|
|
28395
|
+
"pi",
|
|
28396
|
+
"default"
|
|
28397
|
+
]);
|
|
28398
|
+
var BUILT_IN_CLAUDE_CODE = {
|
|
28399
|
+
decider: { model: "fable", effort: "high" },
|
|
28400
|
+
"implementer.hard": { model: "opus" },
|
|
28401
|
+
"implementer.standard": { model: "sonnet" },
|
|
28402
|
+
"implementer.mundane": { model: "haiku" },
|
|
28403
|
+
verifier: { model: "sonnet" },
|
|
28404
|
+
reviewer: { model: "opus" },
|
|
28405
|
+
explore: { model: "haiku" },
|
|
28406
|
+
babysit: { model: "haiku" }
|
|
28407
|
+
};
|
|
28408
|
+
var isObject7 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
28409
|
+
var name = (value) => typeof value === "string" && value.trim() ? value.trim() : null;
|
|
28410
|
+
var leaf = (value) => {
|
|
28411
|
+
const text = name(value);
|
|
28412
|
+
if (text)
|
|
28413
|
+
return { model: text, effort: null };
|
|
28414
|
+
if (!isObject7(value))
|
|
28415
|
+
return null;
|
|
28416
|
+
const model = name(value.model);
|
|
28417
|
+
return model ? { model, effort: name(value.effort) } : null;
|
|
28418
|
+
};
|
|
28419
|
+
var isFlat = (value) => typeof value === "string" || isObject7(value) && Object.hasOwn(value, "model");
|
|
28420
|
+
var forHost = (value, host) => {
|
|
28421
|
+
if (isFlat(value))
|
|
28422
|
+
return leaf(value);
|
|
28423
|
+
if (!isObject7(value))
|
|
28424
|
+
return null;
|
|
28425
|
+
const family = host ? hostFamily(host) : null;
|
|
28426
|
+
for (const key of [family, host, "default"])
|
|
28427
|
+
if (key && Object.hasOwn(value, key)) {
|
|
28428
|
+
const found = leaf(value[key]);
|
|
28429
|
+
if (found)
|
|
28430
|
+
return found;
|
|
28431
|
+
}
|
|
28432
|
+
return null;
|
|
28433
|
+
};
|
|
28434
|
+
var rolesOf = (models) => isObject7(models) && isObject7(models.roles) ? models.roles : null;
|
|
28435
|
+
var resolveRoleModel = (cwd, selector, host, dir) => {
|
|
28436
|
+
const { role, tier } = selector;
|
|
28437
|
+
for (const source of modelSources(cwd, dir)) {
|
|
28438
|
+
const where = source.global ? "the global default" : `workspace ${source.name}`;
|
|
28439
|
+
const roles = rolesOf(source.models);
|
|
28440
|
+
const configured = roles && Object.hasOwn(roles, role) ? roles[role] : undefined;
|
|
28441
|
+
const fromRoles = role === "implementer" ? tier && isObject7(configured) && Object.hasOwn(configured, tier) ? forHost(configured[tier], host) : null : forHost(configured, host);
|
|
28442
|
+
if (fromRoles)
|
|
28443
|
+
return { ...fromRoles, source: `models.roles in ${where}` };
|
|
28444
|
+
if (role === "implementer" && tier && isObject7(source.tierModels)) {
|
|
28445
|
+
const fromTiers = Object.hasOwn(source.tierModels, tier) ? forHost(source.tierModels[tier], host) : null;
|
|
28446
|
+
if (fromTiers)
|
|
28447
|
+
return { model: fromTiers.model, effort: null, source: `fanout.tierModels in ${where}` };
|
|
28448
|
+
}
|
|
28449
|
+
}
|
|
28450
|
+
if (host && hostFamily(host) === "claude_code") {
|
|
28451
|
+
const builtIn = BUILT_IN_CLAUDE_CODE[tier ? `${role}.${tier}` : role];
|
|
28452
|
+
if (builtIn)
|
|
28453
|
+
return { model: builtIn.model, effort: builtIn.effort ?? null, source: "built-in" };
|
|
28454
|
+
}
|
|
28455
|
+
return null;
|
|
28456
|
+
};
|
|
28457
|
+
var uniformImplementerModel = (cwd, host, dir) => {
|
|
28458
|
+
const tiers = MODEL_TIERS.map((tier) => resolveRoleModel(cwd, { role: "implementer", tier }, host, dir));
|
|
28459
|
+
const [first] = tiers;
|
|
28460
|
+
return first && tiers.every((t) => t?.model === first.model && t.effort === first.effort) ? first : null;
|
|
28461
|
+
};
|
|
28462
|
+
var ROLE_SELECTORS = MODEL_ROLES.flatMap((role) => role === "implementer" ? MODEL_TIERS.map((tier) => ({ role, tier })) : [{ role }]);
|
|
28463
|
+
|
|
28346
28464
|
// packages/workit-codex/scripts/agents.ts
|
|
28347
28465
|
import {
|
|
28348
28466
|
existsSync as existsSync10,
|
|
@@ -28356,13 +28474,26 @@ import {
|
|
|
28356
28474
|
} from "node:fs";
|
|
28357
28475
|
import os5 from "node:os";
|
|
28358
28476
|
import path25 from "node:path";
|
|
28477
|
+
var CODEX_AGENT_ROLES = ["verifier", "reviewer", "implementer"];
|
|
28359
28478
|
var CODEX_AGENT_MARKER = "# Generated by Workit";
|
|
28479
|
+
var codexAgentName = (role) => `workit-${role}`;
|
|
28480
|
+
var codexAgentFile = (role) => `${codexAgentName(role)}.toml`;
|
|
28481
|
+
var tomlString = (value) => JSON.stringify(value);
|
|
28360
28482
|
var codexHomeOfInstall = (pluginRoot) => {
|
|
28361
28483
|
const parts = path25.resolve(pluginRoot).split(path25.sep);
|
|
28362
28484
|
const cache = parts.length - 4;
|
|
28363
28485
|
return cache >= 2 && parts[cache] === "cache" && parts[cache - 1] === "plugins" ? parts.slice(0, cache - 1).join(path25.sep) || path25.sep : null;
|
|
28364
28486
|
};
|
|
28365
28487
|
var codexHomeFor = (pluginRoot, env) => codexHomeOfInstall(pluginRoot) ?? (env.CODEX_HOME || path25.join(env.HOME || os5.homedir(), ".codex"));
|
|
28488
|
+
var withRoleModel = (content, file, models) => {
|
|
28489
|
+
const role = CODEX_AGENT_ROLES.find((candidate) => codexAgentFile(candidate) === file);
|
|
28490
|
+
const chosen = role ? models[role] : undefined;
|
|
28491
|
+
if (!chosen)
|
|
28492
|
+
return content;
|
|
28493
|
+
return content.replace(/^(description = .*)$/m, (line) => `${line}
|
|
28494
|
+
model = ${tomlString(chosen.model)}${chosen.effort ? `
|
|
28495
|
+
model_reasoning_effort = ${tomlString(chosen.effort)}` : ""}`);
|
|
28496
|
+
};
|
|
28366
28497
|
var MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
|
|
28367
28498
|
var agentMarkerVersion = (text) => MARKER_VERSION.exec(text)?.[1] ?? null;
|
|
28368
28499
|
var stampCodexAgent = (content, version) => version && content.startsWith(CODEX_AGENT_MARKER) && !agentMarkerVersion(content) ? `${CODEX_AGENT_MARKER} ${version}${content.slice(CODEX_AGENT_MARKER.length)}` : content;
|
|
@@ -28389,7 +28520,7 @@ var lstatOrNull = (file) => {
|
|
|
28389
28520
|
return null;
|
|
28390
28521
|
}
|
|
28391
28522
|
};
|
|
28392
|
-
var installCodexAgents = (pluginRoot, codexHome) => {
|
|
28523
|
+
var installCodexAgents = (pluginRoot, codexHome, models = {}) => {
|
|
28393
28524
|
const source = path25.join(pluginRoot, "agents");
|
|
28394
28525
|
if (!existsSync10(source))
|
|
28395
28526
|
return [];
|
|
@@ -28397,7 +28528,7 @@ var installCodexAgents = (pluginRoot, codexHome) => {
|
|
|
28397
28528
|
const target = path25.join(codexHome, "agents");
|
|
28398
28529
|
const results = [];
|
|
28399
28530
|
for (const file of readdirSync5(source).filter((name) => name.endsWith(".toml")).toSorted()) {
|
|
28400
|
-
const content = stampCodexAgent(readFileSync8(path25.join(source, file), "utf8"), version);
|
|
28531
|
+
const content = withRoleModel(stampCodexAgent(readFileSync8(path25.join(source, file), "utf8"), version), file, models);
|
|
28401
28532
|
const dest = path25.join(target, file);
|
|
28402
28533
|
const stat = lstatOrNull(dest);
|
|
28403
28534
|
if (stat?.isSymbolicLink()) {
|
|
@@ -28497,12 +28628,24 @@ var codexContextProvider = (host = detectCodexSurface(process.env), root) => ({
|
|
|
28497
28628
|
}
|
|
28498
28629
|
});
|
|
28499
28630
|
var pluginRoot = () => path26.resolve(path26.dirname(fileURLToPath3(import.meta.url)), "..");
|
|
28500
|
-
var
|
|
28631
|
+
var codexRoleModels = (cwd) => {
|
|
28632
|
+
const out = {};
|
|
28633
|
+
for (const role of ["verifier", "reviewer"]) {
|
|
28634
|
+
const found = resolveRoleModel(cwd, { role }, "codex");
|
|
28635
|
+
if (found)
|
|
28636
|
+
out[role] = { model: found.model, effort: found.effort };
|
|
28637
|
+
}
|
|
28638
|
+
const implementer = uniformImplementerModel(cwd, "codex");
|
|
28639
|
+
if (implementer)
|
|
28640
|
+
out.implementer = { model: implementer.model, effort: implementer.effort };
|
|
28641
|
+
return out;
|
|
28642
|
+
};
|
|
28643
|
+
var syncCodexAgents = (root, cwd) => {
|
|
28501
28644
|
const codexHome = codexHomeOfInstall(root);
|
|
28502
28645
|
if (!codexHome)
|
|
28503
28646
|
return;
|
|
28504
28647
|
try {
|
|
28505
|
-
installCodexAgents(root, codexHome);
|
|
28648
|
+
installCodexAgents(root, codexHome, codexRoleModels(cwd ?? resolveCodexWorkspaceRoot(root, process.env) ?? process.cwd()));
|
|
28506
28649
|
} catch {}
|
|
28507
28650
|
};
|
|
28508
28651
|
if (__require.main == __require.module) {
|
|
@@ -28523,6 +28666,7 @@ if (__require.main == __require.module) {
|
|
|
28523
28666
|
export {
|
|
28524
28667
|
codexContextProvider,
|
|
28525
28668
|
codexQualification,
|
|
28669
|
+
codexRoleModels,
|
|
28526
28670
|
resolveCodexWorkspaceRoot,
|
|
28527
28671
|
syncCodexAgents
|
|
28528
28672
|
};
|
|
@@ -8472,6 +8472,7 @@ var workspaceConfigSchema = object({
|
|
|
8472
8472
|
trailers: boolean2().optional(),
|
|
8473
8473
|
liveSessionGuard: boolean2().optional(),
|
|
8474
8474
|
fanout: object({ tierModels: unknown().optional() }).passthrough().optional(),
|
|
8475
|
+
models: object({ roles: unknown().optional() }).passthrough().optional(),
|
|
8475
8476
|
autonomy: object(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
|
|
8476
8477
|
kind,
|
|
8477
8478
|
union([boolean2(), literal("verified")]).optional()
|
|
@@ -8498,7 +8499,10 @@ var workspaceConfigSchema = object({
|
|
|
8498
8499
|
});
|
|
8499
8500
|
}
|
|
8500
8501
|
});
|
|
8501
|
-
var workspacesFileSchema = object({
|
|
8502
|
+
var workspacesFileSchema = object({
|
|
8503
|
+
workspaces: array(workspaceConfigSchema).optional(),
|
|
8504
|
+
models: object({ roles: unknown().optional() }).passthrough().optional()
|
|
8505
|
+
}).passthrough().superRefine((file, context) => {
|
|
8502
8506
|
const names = new Set;
|
|
8503
8507
|
for (const [index, workspace] of (file.workspaces ?? []).entries()) {
|
|
8504
8508
|
if (names.has(workspace.name)) {
|
|
@@ -19743,7 +19747,6 @@ var ALLOWED = new Set(WORKIT_ALLOWED_VERBS);
|
|
|
19743
19747
|
var isBypass = (word) => WORKIT_BYPASS_FLAGS.some((flag) => word === flag || word.startsWith(`${flag}=`));
|
|
19744
19748
|
var isWorkitWord = (word) => /^(?:.*[\\/])?workit(?:-cli)?$/u.test(word);
|
|
19745
19749
|
var bypassReason = (flag) => `Workit: \`${flag}\` overrides a Workit gate, so the user decides this call (no allow rule covers it).`;
|
|
19746
|
-
var EXPANSION_REASON = "Workit: an expansion before `--` could become a bypass flag, so the user decides this call (no allow rule covers it).";
|
|
19747
19750
|
var workitBypassFlag = (command, dialect = "posix") => {
|
|
19748
19751
|
for (const segment of segmentsOf(command, dialect)) {
|
|
19749
19752
|
if (segment.unanalyzable) {
|
|
@@ -19761,9 +19764,6 @@ var workitBypassFlag = (command, dialect = "posix") => {
|
|
|
19761
19764
|
const flag = (end < 0 ? words : words.slice(0, end)).find(isBypass);
|
|
19762
19765
|
if (flag)
|
|
19763
19766
|
return bypassReason(flag.split("=")[0] ?? flag);
|
|
19764
|
-
const limit = start + 1 + (end < 0 ? words.length : end);
|
|
19765
|
-
if (segment.expands?.some((index) => index > start && index < limit))
|
|
19766
|
-
return EXPANSION_REASON;
|
|
19767
19767
|
}
|
|
19768
19768
|
return null;
|
|
19769
19769
|
};
|
package/dist/workit-hook.js
CHANGED
|
@@ -49,6 +49,6 @@ if (quiet)
|
|
|
49
49
|
process.stdout.write(`${JSON.stringify({ hookSpecificOutput: { hookEventName: quiet } })}
|
|
50
50
|
`);
|
|
51
51
|
else {
|
|
52
|
-
const { runCodexHook } = await import("./workit-hook-
|
|
52
|
+
const { runCodexHook } = await import("./workit-hook-sza2zvq6.js");
|
|
53
53
|
await runCodexHook([payload]);
|
|
54
54
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-codex",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.26.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit Codex CLI/desktop plugin — shared MCP transport, hooks, method skills, and verifier/reviewer/implementer agents",
|
|
6
6
|
"keywords": [
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"build": "bun scripts/build.ts"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@brainervirus/workit-core": "^8.
|
|
43
|
-
"@brainervirus/workit-mcp": "^8.
|
|
42
|
+
"@brainervirus/workit-core": "^8.26.1",
|
|
43
|
+
"@brainervirus/workit-mcp": "^8.26.1"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
|
46
46
|
"node": ">=24"
|
|
@@ -25,8 +25,8 @@ units of ~100+ lines each. Coupled work stays with one owner. Workit never spawn
|
|
|
25
25
|
Never hand-edit it; change the plan or the standing orders and render again.
|
|
26
26
|
4. **Spawn in a rolling window**, in the background, each in its own worktree:
|
|
27
27
|
keep 4-6 in flight and refill from `spawnable` in `workit fanout status` as
|
|
28
|
-
each one finishes. Model: the brief's `model:`
|
|
29
|
-
(`references/orchestration.md`). Claude Code: the `implementer` agent, never
|
|
28
|
+
each one finishes. Model: the brief's `model:` and `effort:` lines (`workit models show`),
|
|
29
|
+
else TIER (`references/orchestration.md`). Claude Code: the `implementer` agent, never
|
|
30
30
|
with `isolation: "worktree"`; Workit's hooks confine it to its WORKTREE.
|
|
31
31
|
5. **Judge liveness by side effects only:** `workit fanout status` (head age,
|
|
32
32
|
PR, CI, verdict, landed; STUCK past the TIMEBOX). Stop a stuck worker and
|
|
@@ -40,12 +40,12 @@ units of ~100+ lines each. Coupled work stays with one owner. Workit never spawn
|
|
|
40
40
|
chain resumes. A fix round and recheck that both fail: a decider, not a
|
|
41
41
|
third round; product choices go to the user (`references/orchestration.md`).
|
|
42
42
|
7. **Verify by the workspace `verification` setting** (`workit grant show`).
|
|
43
|
-
A report is a pointer, never evidence. `proportional` (default): each slice's lane (`workit pr status`) decides; none needs no verdict, self the author's `--self`, focused
|
|
43
|
+
A report is a pointer, never evidence. `proportional` (default): each slice's lane (`workit pr status`) decides; none needs no verdict, self the author's `--self`, focused and full a verifier (Claude Code: the `model` and `effort` of `workit models show --role verifier`) after the last push; one verdict at a stack's top covers its unchanged lower PRs, and a stale one with `reverify: focused` re-checks only the new diff, reusing green CI. `self`: a verifier that wrote none
|
|
44
44
|
of the slices, or you if you wrote none. `independent` or high risk: a
|
|
45
45
|
separate verifier session, never yours (doctrine: the ledger only refuses
|
|
46
46
|
authors). One verifier may take a batch of slices, one verdict per branch
|
|
47
47
|
(`workit ledger verdict <result> --branch <b> --how "<evidence>"`), in a
|
|
48
|
-
session never chosen by the author. A review panel on separate models only at high risk.
|
|
48
|
+
session never chosen by the author. Spawn it with the brief's `verifier:` model (`workit models show --role verifier`). A review panel on separate models only at high risk.
|
|
49
49
|
8. **Fan in** with `workit fanout check`: out-of-scope files (any file outside
|
|
50
50
|
it stops the fan-in) and `git merge-tree` conflicts with trunk and between
|
|
51
51
|
siblings. Fix what it names until it exits 0; a merged slice reads as
|
|
@@ -5,22 +5,31 @@ and fans in. Workit records and checks; the host's own subagents run the work.
|
|
|
5
5
|
|
|
6
6
|
## TIER to model
|
|
7
7
|
|
|
8
|
-
TIER is a field of each slice and of its brief.
|
|
9
|
-
`fanout.tierModels
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
8
|
+
TIER is a field of each slice and of its brief. Role models come from the
|
|
9
|
+
workspace (`models.roles`; `fanout.tierModels` still feeds the implementer
|
|
10
|
+
tiers) and, on Claude Code, built-in defaults: the brief has a `model:` line
|
|
11
|
+
(with `effort:` when set) under TIER and a `verifier:` line; `workit fanout
|
|
12
|
+
status` names the model next to each spawnable slice; `workit models show
|
|
13
|
+
[--role r] [--host h] --json` lists every role (decider, implementer tiers,
|
|
14
|
+
verifier, reviewer, explore, babysit). Pass exactly that `model` (and `effort`
|
|
15
|
+
where the host's spawn call takes one) on the spawn call: a subagent that
|
|
16
|
+
passes none inherits your model. Scouting and PR babysitting use the `explore`
|
|
17
|
+
and `babysit` roles. A role with no model (other hosts without config) runs
|
|
18
|
+
on the host's model, and TIER only sizes the timebox and decides whether to
|
|
19
|
+
race. Claude Code's built-in defaults, when nothing is configured:
|
|
20
|
+
|
|
21
|
+
| Role or TIER | `model` on the Agent call |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| decider | `fable`, effort `high` |
|
|
24
|
+
| hard | `opus` |
|
|
25
|
+
| standard | `sonnet` |
|
|
26
|
+
| mundane | `haiku` |
|
|
27
|
+
| verifier | `sonnet` |
|
|
28
|
+
| reviewer | `opus` |
|
|
29
|
+
| explore, babysit | `haiku` |
|
|
30
|
+
|
|
31
|
+
OpenCode takes a subagent's model from its agent config: pick a
|
|
32
|
+
configured agent whose model fits the TIER, else the default.
|
|
24
33
|
|
|
25
34
|
## Rolling window
|
|
26
35
|
|
|
@@ -53,7 +62,7 @@ reversibility (the option cheapest to undo wins a tie), and the exact change
|
|
|
53
62
|
list. The fixer applies that list once, then one focused recheck follows.
|
|
54
63
|
|
|
55
64
|
- Hard call (shared contract, security, migration): two deciders on different
|
|
56
|
-
models (Claude Code: a different `model` on the Agent call; OpenCode: a
|
|
65
|
+
models (Claude Code: the `decider` role model, the other a different `model` on the Agent call; OpenCode: a
|
|
57
66
|
child session on another configured agent; Codex, Cursor and Pi: one
|
|
58
67
|
decider, since the host picks no model). If they disagree, you take the
|
|
59
68
|
more reversible option.
|
|
@@ -40,7 +40,7 @@ description: Build a requested change in small verified steps - follow local pat
|
|
|
40
40
|
status`). Lane none: no verdict. Lane self: after `workit check test` passes,
|
|
41
41
|
record `workit ledger verdict tests-verified --self --how "<what you ran>"`;
|
|
42
42
|
it reads self-reviewed, never verified, and is enough. Focused, full, high
|
|
43
|
-
risk or `verification: self|independent` merges: one fresh verifier per PR after the last push, its own host-derived session (Claude Code: the `verifier` agent
|
|
43
|
+
risk or `verification: self|independent` merges: one fresh verifier per PR after the last push, its own host-derived session (Claude Code: the `verifier` agent with the `model` (and `effort`) of `workit models show --role verifier`; Codex:
|
|
44
44
|
the `verifier` agent; OpenCode: a child session; Pi: a supervised worker),
|
|
45
45
|
never a hand-minted id. Before saying done, reconcile
|
|
46
46
|
every named deliverable against the target checkout and observe it (for a push:
|
|
@@ -9,7 +9,8 @@ Review the candidate, never the author's summary of it. A session that wrote a
|
|
|
9
9
|
commit on the branch cannot record a passing verdict: if that is you, hand the
|
|
10
10
|
review to a fresh agent with its own host-derived session: Claude Code and
|
|
11
11
|
Codex, the `reviewer` or `verifier` agent (`--session` and `--token` from SubagentStart);
|
|
12
|
-
OpenCode, a child session; Pi, a supervised worker.
|
|
12
|
+
OpenCode, a child session; Pi, a supervised worker. On Claude Code pass the
|
|
13
|
+
`model` and `effort` of `workit models show --role <verifier|reviewer>`. Never hand-mint one such
|
|
13
14
|
as `<lead>-v1`: it is refused as `forged_session`.
|
|
14
15
|
An author's `--self` verdict reads self-reviewed and never counts as
|
|
15
16
|
independent; `type-check-only` never proves a behavior change.
|
|
@@ -51,7 +51,7 @@ the same check. Fix round and recheck both failed: a decider (read the `workit-f
|
|
|
51
51
|
allows; no sleep loop. Red: read `logTail`, classify. Flake or infra: one
|
|
52
52
|
`workit ci rerun --failed --reason flake|infra` per head. Real: reproduce
|
|
53
53
|
with `workit check`, fix the root cause, batch every fix in one push.
|
|
54
|
-
6. **Verified.** The lane in `workit pr status` decides: none, no verdict; self, your `--self` verdict; focused or full (or `verification: self|independent`), one non-author verifier per PR after the last push, never per push (read the `workit-review` skill's SKILL.md and follow it), on Claude Code `model
|
|
54
|
+
6. **Verified.** The lane in `workit pr status` decides: none, no verdict; self, your `--self` verdict; focused or full (or `verification: self|independent`), one non-author verifier per PR after the last push, never per push (read the `workit-review` skill's SKILL.md and follow it), on Claude Code with the `model` and `effort` of `workit models show --role verifier`. A docs-only push (or test-only under a unit verdict) keeps the verdict (`carried`); `reverify: focused` re-checks only the new diff, reusing green CI; one verdict at a stack's top covers its unchanged lower PRs. Land only when
|
|
55
55
|
granted: `workit stack land` or `workit pr merge`; `--unverified --reason` if user-asked.
|
|
56
56
|
7. **Observe it landed:** `workit verify-delivery pr` or `merge`. After a failed
|
|
57
57
|
verdict or a check red 3+ times, at any endpoint: offer `/wk-retro` in one
|