agent-bios 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DEPENDENCIES.md +1 -0
- package/README.md +2 -1
- package/claude/CLAUDE.md +14 -5
- package/claude/agents/frontier.md +9 -0
- package/claude/agents/sweep.md +9 -0
- package/claude/agents/workhorse.md +8 -0
- package/claude/guides/cli-multi-model-workflow.md +17 -4
- package/claude/guides/coding-staged-workflow.md +8 -0
- package/claude/guides/llm-capability-boundary-patterns.md +5 -0
- package/claude/guides/mock-realization-boundary.md +9 -0
- package/claude/guides/review-request.md +8 -0
- package/claude/guides/session-distill-workflow.md +100 -0
- package/claude/guides/tooling-gotchas.md +155 -0
- package/claude/hooks/tooling-gotchas-hook.py +79 -0
- package/codex/AGENTS.md +14 -5
- package/codex/config-additions.toml +22 -0
- package/codex/guides/cli-multi-model-workflow.md +17 -4
- package/codex/guides/coding-staged-workflow.md +8 -0
- package/codex/guides/llm-capability-boundary-patterns.md +5 -0
- package/codex/guides/mock-realization-boundary.md +9 -0
- package/codex/guides/review-request.md +8 -0
- package/codex/guides/session-distill-workflow.md +100 -0
- package/codex/guides/tooling-gotchas.md +155 -0
- package/config/agent-launch.toml +43 -0
- package/package.json +4 -1
- package/scripts/agent-launch.py +486 -52
- package/scripts/check-parity.sh +154 -7
- package/scripts/codex-helm.sh +19 -1
- package/scripts/codex-run.sh +19 -0
- package/scripts/install.sh +271 -10
package/scripts/check-parity.sh
CHANGED
|
@@ -111,8 +111,41 @@ current-state dashboard|claude/CLAUDE.md|claude/guides/implementation-map.md
|
|
|
111
111
|
Verification Menus|claude/CLAUDE.md|claude/guides/coding-staged-workflow.md
|
|
112
112
|
real Microsoft Excel engine|claude/CLAUDE.md|claude/guides/coding-staged-workflow.md
|
|
113
113
|
severity contract|README.md|claude/guides/coding-staged-workflow.md
|
|
114
|
+
Ambient state|claude/CLAUDE.md|claude/guides/tooling-gotchas.md
|
|
115
|
+
the full lifecycle of what you create|claude/CLAUDE.md|claude/guides/tooling-gotchas.md
|
|
116
|
+
dual-provider frontier design drafts|claude/CLAUDE.md|claude/guides/cli-multi-model-workflow.md
|
|
114
117
|
ANCHORS
|
|
115
118
|
|
|
119
|
+
# Domain-manifest gate: bullet<->anchor bijection, file coverage, router
|
|
120
|
+
# co-packaging (config/domains.json vs the monolith); its --self-test proves
|
|
121
|
+
# every negative control still fails, so a green gate is falsifiable.
|
|
122
|
+
if [ -f config/domains.json ]; then
|
|
123
|
+
python3 scripts/check-domains.py >/dev/null \
|
|
124
|
+
|| { echo "FAIL: domains manifest gate (run scripts/check-domains.py)"; fail=1; }
|
|
125
|
+
python3 scripts/check-domains.py --self-test >/dev/null \
|
|
126
|
+
|| { echo "FAIL: domains gate self-test missed a negative control"; fail=1; }
|
|
127
|
+
bash scripts/test-assemble.sh >/dev/null \
|
|
128
|
+
|| { echo "FAIL: assembler scenario suite (run scripts/test-assemble.sh)"; fail=1; }
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# Learning record gate: config/learning.schema.json (collection-loop
|
|
132
|
+
# SSOT) vs its fixtures; --self-test proves every mutation is still caught.
|
|
133
|
+
if [ -f config/learning.schema.json ]; then
|
|
134
|
+
python3 scripts/check-learning.py >/dev/null \
|
|
135
|
+
|| { echo "FAIL: learning record gate (run scripts/check-learning.py)"; fail=1; }
|
|
136
|
+
python3 scripts/check-learning.py --self-test >/dev/null \
|
|
137
|
+
|| { echo "FAIL: learning gate self-test missed a negative control"; fail=1; }
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
# Lexicon gate: forbid deprecated terminology tokens in live files
|
|
141
|
+
# (LEXICON.md is the SSOT); --self-test proves the detector can fire.
|
|
142
|
+
if [ -f LEXICON.md ]; then
|
|
143
|
+
python3 scripts/check-lexicon.py >/dev/null \
|
|
144
|
+
|| { echo "FAIL: lexicon gate (run scripts/check-lexicon.py)"; fail=1; }
|
|
145
|
+
python3 scripts/check-lexicon.py --self-test >/dev/null \
|
|
146
|
+
|| { echo "FAIL: lexicon gate self-test failed"; fail=1; }
|
|
147
|
+
fi
|
|
148
|
+
|
|
116
149
|
# The launcher's Textual preflight UI tests need the managed venv (textual).
|
|
117
150
|
# Provision it if missing; every non-UI check above runs under system python.
|
|
118
151
|
VENV="${AGENT_LAUNCH_VENV:-$HOME/.local/share/agent-launch/venv}"
|
|
@@ -264,6 +297,33 @@ for filename, (expected_name, expected_model, expected_effort) in expected_agent
|
|
|
264
297
|
f"want {expected_effort!r}"
|
|
265
298
|
)
|
|
266
299
|
|
|
300
|
+
# codex/config-additions.toml is the additive fragment install merges into the
|
|
301
|
+
# live ~/.codex/config.toml; its agent entries are projections of the canonical
|
|
302
|
+
# codex/agents/*.toml templates and must not drift from them.
|
|
303
|
+
fragment_path = pathlib.Path("codex/config-additions.toml")
|
|
304
|
+
if not fragment_path.is_file():
|
|
305
|
+
mark_fail("required file missing: codex/config-additions.toml")
|
|
306
|
+
else:
|
|
307
|
+
fragment = tomllib.loads(fragment_path.read_text())
|
|
308
|
+
if fragment.get("features", {}).get("multi_agent") is not True:
|
|
309
|
+
mark_fail("config-additions must set features.multi_agent = true")
|
|
310
|
+
fragment_agents = fragment.get("agents", {})
|
|
311
|
+
if set(fragment_agents) != {"frontier", "workhorse", "sweep"}:
|
|
312
|
+
mark_fail(
|
|
313
|
+
"config-additions agents must be exactly the spawnable tiers "
|
|
314
|
+
f"(no helm): {sorted(fragment_agents)}"
|
|
315
|
+
)
|
|
316
|
+
for tier, spec in fragment_agents.items():
|
|
317
|
+
template_path = agent_dir / f"{tier}.toml"
|
|
318
|
+
template = tomllib.loads(template_path.read_text()) if template_path.is_file() else {}
|
|
319
|
+
if spec.get("description") != template.get("description"):
|
|
320
|
+
mark_fail(f"config-additions {tier} description drifted from {template_path}")
|
|
321
|
+
if spec.get("config_file") != f"${{CODEX_HOME}}/agents/{tier}.toml":
|
|
322
|
+
mark_fail(
|
|
323
|
+
f"config-additions {tier} config_file must be "
|
|
324
|
+
f"${{CODEX_HOME}}/agents/{tier}.toml"
|
|
325
|
+
)
|
|
326
|
+
|
|
267
327
|
|
|
268
328
|
def table_row(path, slot):
|
|
269
329
|
for raw_line in path.read_text().splitlines():
|
|
@@ -522,7 +582,9 @@ if launcher.is_file() and launch_profile:
|
|
|
522
582
|
def set_plan(self, plan):
|
|
523
583
|
self.plan = plan
|
|
524
584
|
|
|
525
|
-
def choose(self, title, options, default, allow_back, preview=None):
|
|
585
|
+
def choose(self, title, options, default, allow_back, preview=None, corpus_lines=None):
|
|
586
|
+
if title == "Mode":
|
|
587
|
+
return "builder"
|
|
526
588
|
if title == "Preset":
|
|
527
589
|
if preview is not None:
|
|
528
590
|
balanced = launcher_module.setup_summary_lines(preview("balanced"))
|
|
@@ -743,11 +805,17 @@ if launcher.is_file() and launch_profile:
|
|
|
743
805
|
os.close(master)
|
|
744
806
|
return bytes(transcript), picker_status
|
|
745
807
|
|
|
808
|
+
# Root menu is now a Mode picker (General user / Builder / Session
|
|
809
|
+
# distill); Builder is the default highlight and lists Custom. Reaching
|
|
810
|
+
# Custom means: Enter the root to open Builder's preset submenu, then
|
|
811
|
+
# step down through its fixed presets (Balanced default-highlighted).
|
|
746
812
|
open_custom_steps = (
|
|
813
|
+
(b"Esc cancel | q cancel", b"\r"),
|
|
747
814
|
(b"native multi-perspective review", b""),
|
|
748
|
-
(b"Esc
|
|
815
|
+
(b"Esc back | q cancel", b"\x1b[B"),
|
|
749
816
|
(b"hybrid onto", b"\x1b[B"),
|
|
750
817
|
(b"high-volume", b"\x1b[B"),
|
|
818
|
+
(b"the standing spawn policy is lifted", b"\x1b[B"),
|
|
751
819
|
(b"Open a settings hub", b"\r"),
|
|
752
820
|
)
|
|
753
821
|
down = b"\x1b[B"
|
|
@@ -768,7 +836,7 @@ if launcher.is_file() and launch_profile:
|
|
|
768
836
|
b"WORKHORSE",
|
|
769
837
|
b"SWEEP",
|
|
770
838
|
b"About highlighted option",
|
|
771
|
-
b"
|
|
839
|
+
b"Tune tiers, review routes, and permissions",
|
|
772
840
|
b"Options (",
|
|
773
841
|
)
|
|
774
842
|
positions = {token: transcript.find(token) for token in layout_tokens}
|
|
@@ -779,7 +847,7 @@ if launcher.is_file() and launch_profile:
|
|
|
779
847
|
positions[b"Current setup"]
|
|
780
848
|
< min(positions[token] for token in (b"FRONTIER", b"HELM", b"WORKHORSE", b"SWEEP"))
|
|
781
849
|
< positions[b"About highlighted option"]
|
|
782
|
-
< positions[b"
|
|
850
|
+
< positions[b"Tune tiers, review routes, and permissions"]
|
|
783
851
|
< positions[b"Options ("]
|
|
784
852
|
):
|
|
785
853
|
mark_fail("agent-launch layout is not setup then description then options")
|
|
@@ -791,12 +859,27 @@ if launcher.is_file() and launch_profile:
|
|
|
791
859
|
if picker_status != 130:
|
|
792
860
|
mark_fail(f"agent-launch root Esc returned {picker_status}, want 130")
|
|
793
861
|
|
|
862
|
+
# Root Mode picker navigation: Esc from the Builder preset submenu
|
|
863
|
+
# returns to a freshly re-rendered Mode picker (Builder's own
|
|
864
|
+
# description reappears) rather than cancelling the launcher outright.
|
|
865
|
+
_, picker_status = run_picker_scenario(
|
|
866
|
+
"mode picker navigation",
|
|
867
|
+
(
|
|
868
|
+
(b"Esc cancel | q cancel", b"\r"),
|
|
869
|
+
(b"native multi-perspective review", b"\x1b"),
|
|
870
|
+
(b"Tune tiers, review routes, and permissions", b"q"),
|
|
871
|
+
),
|
|
872
|
+
)
|
|
873
|
+
if picker_status != 130:
|
|
874
|
+
mark_fail(f"agent-launch mode picker Esc-back returned {picker_status}, want 130")
|
|
875
|
+
|
|
794
876
|
if argv_log.exists():
|
|
795
877
|
argv_log.unlink()
|
|
796
878
|
_, picker_status = run_picker_scenario(
|
|
797
879
|
"launch confirmation q cancellation",
|
|
798
880
|
(
|
|
799
881
|
(b"Esc cancel | q cancel", b"\r"),
|
|
882
|
+
(b"HELM default for everyday work", b"\r"),
|
|
800
883
|
(b"Launch? [Y/n/q]:", b"q\r"),
|
|
801
884
|
),
|
|
802
885
|
dry_run=False,
|
|
@@ -1098,10 +1181,20 @@ if launcher.is_file() and launch_profile:
|
|
|
1098
1181
|
# TERM=dumb routes to numbered prompts (textual renders on any usable
|
|
1099
1182
|
# terminal, so the numbered fallback is gated on TERM/non-TTY/textual
|
|
1100
1183
|
# availability, not a terminfo probe). 'b' is the numbered back command.
|
|
1184
|
+
# The root Mode menu is fixed (General=1, Builder=2, Session distill=3)
|
|
1185
|
+
# regardless of preset count; only Custom's position within Builder's
|
|
1186
|
+
# own preset submenu depends on how many builder-mode presets exist.
|
|
1187
|
+
builder_preset_count = sum(
|
|
1188
|
+
1
|
|
1189
|
+
for data in fake_data["presets"].values()
|
|
1190
|
+
if data.get("mode", "builder") == "builder"
|
|
1191
|
+
)
|
|
1192
|
+
custom_number = str(builder_preset_count + 1).encode()
|
|
1101
1193
|
transcript, picker_status = run_picker_scenario(
|
|
1102
1194
|
"numbered fallback (TERM=dumb)",
|
|
1103
1195
|
(
|
|
1104
|
-
(b"
|
|
1196
|
+
(b"Tune tiers, review routes, and permissions", b"2\n"),
|
|
1197
|
+
(b"Open a settings hub", custom_number + b"\n"),
|
|
1105
1198
|
(b"Custom settings", b"b\n"),
|
|
1106
1199
|
(b"HELM default for everyday work", b"1\n"),
|
|
1107
1200
|
),
|
|
@@ -1114,6 +1207,28 @@ if launcher.is_file() and launch_profile:
|
|
|
1114
1207
|
):
|
|
1115
1208
|
mark_fail("agent-launch numbered fallback (TERM=dumb) did not preserve numbered back")
|
|
1116
1209
|
|
|
1210
|
+
# Session Distill hub: enter, render status, back out, launch balanced.
|
|
1211
|
+
transcript, picker_status = run_picker_scenario(
|
|
1212
|
+
"numbered distill hub (TERM=dumb)",
|
|
1213
|
+
(
|
|
1214
|
+
(b"Session distill", b"3\n"),
|
|
1215
|
+
(b"Versions & rollback", b"4\n"),
|
|
1216
|
+
(b"Tune tiers, review routes, and permissions", b"2\n"),
|
|
1217
|
+
(b"HELM default for everyday work", b"1\n"),
|
|
1218
|
+
),
|
|
1219
|
+
term="dumb",
|
|
1220
|
+
)
|
|
1221
|
+
corpus_panel_rendered = (
|
|
1222
|
+
b"Applied version" in transcript or b"not projected yet" in transcript
|
|
1223
|
+
)
|
|
1224
|
+
if (
|
|
1225
|
+
picker_status != 0
|
|
1226
|
+
or b"Traceback" in transcript
|
|
1227
|
+
or not corpus_panel_rendered
|
|
1228
|
+
or b"Preset Balanced" not in transcript
|
|
1229
|
+
):
|
|
1230
|
+
mark_fail("agent-launch numbered distill hub did not render or return")
|
|
1231
|
+
|
|
1117
1232
|
passed = invoke([
|
|
1118
1233
|
sys.executable, str(launcher), "--no-tui", "codex", "--", "exec", "--json", "probe"
|
|
1119
1234
|
], env=env)
|
|
@@ -1421,7 +1536,16 @@ if launcher.is_file() and launch_profile:
|
|
|
1421
1536
|
except (ValueError, IndexError, json.JSONDecodeError) as exc:
|
|
1422
1537
|
mark_fail(f"agent-launch Claude --agents projection is not valid JSON: {exc}")
|
|
1423
1538
|
else:
|
|
1424
|
-
|
|
1539
|
+
expected_spawnable = {
|
|
1540
|
+
tier: expected_claude_tiers[tier]
|
|
1541
|
+
for tier in ("frontier", "workhorse", "sweep")
|
|
1542
|
+
}
|
|
1543
|
+
if set(agents_arg) != set(expected_spawnable):
|
|
1544
|
+
mark_fail(
|
|
1545
|
+
"Claude --agents must project exactly the spawnable tiers "
|
|
1546
|
+
f"(HELM is the main, never a subagent): {sorted(agents_arg)}"
|
|
1547
|
+
)
|
|
1548
|
+
for tier, (model, effort) in expected_spawnable.items():
|
|
1425
1549
|
role = agents_arg.get(tier, {})
|
|
1426
1550
|
if role.get("model") != model or role.get("effort") != effort:
|
|
1427
1551
|
mark_fail(f"agent-launch Claude {tier} role projection drifted: {role!r}")
|
|
@@ -1430,6 +1554,29 @@ if launcher.is_file() and launch_profile:
|
|
|
1430
1554
|
"agent-launch Claude expert overrides were not appended last"
|
|
1431
1555
|
)
|
|
1432
1556
|
|
|
1557
|
+
# Vanilla (mode=general): the raw backend with nothing applied — no
|
|
1558
|
+
# launch contract, no agents, no permission-bypass flag.
|
|
1559
|
+
vanilla_configured = invoke([
|
|
1560
|
+
sys.executable, str(launcher), "--preset", "vanilla", "--yes", "--dry-run",
|
|
1561
|
+
"claude",
|
|
1562
|
+
], env=env)
|
|
1563
|
+
if vanilla_configured.returncode != 0:
|
|
1564
|
+
mark_fail(
|
|
1565
|
+
f"agent-launch vanilla dry-run failed: {vanilla_configured.stderr.strip()}"
|
|
1566
|
+
)
|
|
1567
|
+
else:
|
|
1568
|
+
vanilla_argv = json.loads(vanilla_configured.stdout.splitlines()[-1])
|
|
1569
|
+
for forbidden in (
|
|
1570
|
+
"--append-system-prompt", "--agents", "--dangerously-skip-permissions",
|
|
1571
|
+
):
|
|
1572
|
+
if forbidden in vanilla_argv:
|
|
1573
|
+
mark_fail(f"agent-launch vanilla preset unexpectedly carried {forbidden}")
|
|
1574
|
+
if vanilla_argv != [str(backend)]:
|
|
1575
|
+
mark_fail(
|
|
1576
|
+
"agent-launch vanilla preset must project the bare backend with "
|
|
1577
|
+
f"nothing applied: {vanilla_argv!r}"
|
|
1578
|
+
)
|
|
1579
|
+
|
|
1433
1580
|
# Cross-family default: each main routes every review route to the OPPOSITE
|
|
1434
1581
|
# model family, with concrete tools/paths/bindings named in the contract.
|
|
1435
1582
|
# The cross CODEX_HOME needs the reviewer wrappers (bin) and the same-family
|
|
@@ -1704,5 +1851,5 @@ then
|
|
|
1704
1851
|
fail=1
|
|
1705
1852
|
fi
|
|
1706
1853
|
|
|
1707
|
-
[ "$fail" -eq 0 ] && echo "PARITY OK: mirrors, globals, guides, launch profile, bypass paths, role bindings, and wrapper defaults aligned"
|
|
1854
|
+
[ "$fail" -eq 0 ] && echo "PARITY OK: mirrors, globals, guides, domain manifest, assembler, launch profile, bypass paths, role bindings, and wrapper defaults aligned"
|
|
1708
1855
|
exit "$fail"
|
package/scripts/codex-helm.sh
CHANGED
|
@@ -268,9 +268,27 @@ EOF
|
|
|
268
268
|
EOF
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
# Review packets must carry the whole subject: range-based diffs silently omit
|
|
272
|
+
# staged-but-uncommitted changes and untracked files, so the dispatcher itself
|
|
273
|
+
# appends the subject tree's actual state to the packet.
|
|
274
|
+
scope_note=""
|
|
275
|
+
if [ "$mode" = "review" ] && { [ -n "$cd_dir" ] || [ "$reach" != "hermetic" ]; }; then
|
|
276
|
+
scope_root="${cd_dir:-$PWD}"
|
|
277
|
+
if git -C "$scope_root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
278
|
+
scope_status="$(git -C "$scope_root" status --porcelain 2>/dev/null || true)"
|
|
279
|
+
if [ -n "$scope_status" ]; then
|
|
280
|
+
scope_note="Review scope manifest (dispatcher-generated \`git status --porcelain\` of the subject tree; uncommitted/untracked entries are part of the review subject unless the task says otherwise):
|
|
281
|
+
$scope_status"
|
|
282
|
+
echo "codex-helm: subject tree has uncommitted/untracked entries; scope manifest appended to the packet" >&2
|
|
283
|
+
fi
|
|
284
|
+
fi
|
|
285
|
+
fi
|
|
286
|
+
|
|
271
287
|
final_prompt="$(build_preamble)
|
|
272
288
|
|
|
273
|
-
|
|
289
|
+
${scope_note:+$scope_note
|
|
290
|
+
|
|
291
|
+
}User task:
|
|
274
292
|
$user_prompt"
|
|
275
293
|
|
|
276
294
|
cleanup_dirs=()
|
package/scripts/codex-run.sh
CHANGED
|
@@ -167,6 +167,25 @@ if [ "${#extra_c[@]}" -gt 0 ]; then
|
|
|
167
167
|
for kv in "${extra_c[@]}"; do args+=(-c "$kv"); done
|
|
168
168
|
fi
|
|
169
169
|
|
|
170
|
+
# Dispatch audit: verifier diversity is only as real as the pinned backing
|
|
171
|
+
# model — an unpinned dispatch inherits config defaults and can silently
|
|
172
|
+
# collapse two "different" reviewers onto one backend. The audit line goes to
|
|
173
|
+
# the log file only; stdout/stderr stay reserved for the codex channels.
|
|
174
|
+
sandbox_label="$sandbox"
|
|
175
|
+
if [ "$bypass_sandbox" -eq 1 ]; then sandbox_label="bypass"; fi
|
|
176
|
+
cmodel=""
|
|
177
|
+
if [ "${#extra_c[@]}" -gt 0 ]; then
|
|
178
|
+
for kv in "${extra_c[@]}"; do
|
|
179
|
+
case "$kv" in model=*) cmodel="${kv#model=}" ;; esac
|
|
180
|
+
done
|
|
181
|
+
fi
|
|
182
|
+
dispatch_note="dispatch profile=$profile model=${model:-INHERITED_DEFAULT}${cmodel:+ c-model-override=$cmodel} effort=${effort:-config-default} sandbox=$sandbox_label"
|
|
183
|
+
if [ -z "$model" ] && [ -z "$cmodel" ]; then
|
|
184
|
+
echo "codex-run: WARNING: no --model pin; the backing model inherits the active config default" >&2
|
|
185
|
+
fi
|
|
186
|
+
mkdir -p "$real_home/log" 2>/dev/null || true
|
|
187
|
+
printf '%s %s\n' "$(date +%Y-%m-%dT%H:%M:%S%z)" "$dispatch_note" >> "$real_home/log/codex-run-dispatch.log" 2>/dev/null || true
|
|
188
|
+
|
|
170
189
|
# stdin, stdout, and stderr already match this adapter's channel contract.
|
|
171
190
|
set +e
|
|
172
191
|
CODEX_HOME="$run_home" codex "${args[@]}"
|