agent-bios 0.2.0 → 0.3.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/claude/CLAUDE.md +12 -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 +11 -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-learning-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 +12 -5
- package/codex/config-additions.toml +22 -0
- package/codex/guides/cli-multi-model-workflow.md +11 -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-learning-workflow.md +100 -0
- package/codex/guides/tooling-gotchas.md +155 -0
- package/config/agent-launch.toml +17 -0
- package/package.json +4 -1
- package/scripts/agent-launch.py +357 -12
- package/scripts/check-parity.sh +65 -3
- package/scripts/codex-helm.sh +19 -1
- package/scripts/codex-run.sh +19 -0
- package/scripts/install.sh +162 -2
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[@]}"
|
package/scripts/install.sh
CHANGED
|
@@ -126,6 +126,152 @@ migrate_state() {
|
|
|
126
126
|
mv "$LEGACY_STATE_DIR" "$STATE_DIR" && info "migrated state $LEGACY_STATE_DIR -> $STATE_DIR"
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
# ---- codex live-config additions -----------------------------------------
|
|
130
|
+
# The live ~/.codex/config.toml is user/runtime-owned; agent-bios never
|
|
131
|
+
# deploys or overwrites it. codex/config-additions.toml declares the only
|
|
132
|
+
# content agent-bios manages there — one marked [agents.*] block plus a tagged
|
|
133
|
+
# features.multi_agent line — and this helper merges (install), checks
|
|
134
|
+
# (verify), or removes (uninstall) exactly that content, backed up and
|
|
135
|
+
# tomllib-validated before any write. Modes: merge | check | remove.
|
|
136
|
+
codex_config_additions() {
|
|
137
|
+
AB_MODE="$1" AB_CODEX_DIR="$CODEX_DIR" AB_FRAGMENT="$REPO/codex/config-additions.toml" \
|
|
138
|
+
AB_BACKUP="${BACKUP_DIR:-}" AB_DRY="$DRY_RUN" python3 - <<'PY'
|
|
139
|
+
import os, pathlib, sys, tomllib
|
|
140
|
+
|
|
141
|
+
mode = os.environ["AB_MODE"]
|
|
142
|
+
codex_dir = pathlib.Path(os.environ["AB_CODEX_DIR"])
|
|
143
|
+
fragment_path = pathlib.Path(os.environ["AB_FRAGMENT"])
|
|
144
|
+
backup_root = os.environ.get("AB_BACKUP", "")
|
|
145
|
+
dry = os.environ.get("AB_DRY") == "1"
|
|
146
|
+
target = codex_dir / "config.toml"
|
|
147
|
+
BEGIN = "# >>> agent-bios additions >>>"
|
|
148
|
+
END = "# <<< agent-bios additions <<<"
|
|
149
|
+
TAG = "# agent-bios"
|
|
150
|
+
|
|
151
|
+
def info(msg): print(f" {msg}")
|
|
152
|
+
def fail(msg): print(msg); sys.exit(1)
|
|
153
|
+
|
|
154
|
+
frag_text = fragment_path.read_text().replace("${CODEX_HOME}", str(codex_dir))
|
|
155
|
+
want_agents = tomllib.loads(frag_text)["agents"]
|
|
156
|
+
live_text = target.read_text() if target.is_file() else ""
|
|
157
|
+
try:
|
|
158
|
+
live = tomllib.loads(live_text) if live_text else {}
|
|
159
|
+
except Exception as exc:
|
|
160
|
+
fail(f"live codex config does not parse; not touching it: {target} ({exc})")
|
|
161
|
+
|
|
162
|
+
def state_ok():
|
|
163
|
+
if live.get("features", {}).get("multi_agent") is not True:
|
|
164
|
+
return False
|
|
165
|
+
return all(
|
|
166
|
+
live.get("agents", {}).get(name, {}).get(key) == spec[key]
|
|
167
|
+
for name, spec in want_agents.items()
|
|
168
|
+
for key in ("description", "config_file")
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if mode == "check":
|
|
172
|
+
problems = []
|
|
173
|
+
if live.get("features", {}).get("multi_agent") is not True:
|
|
174
|
+
problems.append("features.multi_agent is not true")
|
|
175
|
+
for name, spec in want_agents.items():
|
|
176
|
+
if live.get("agents", {}).get(name, {}).get("config_file") != spec["config_file"]:
|
|
177
|
+
problems.append(f"agents.{name}.config_file drifted or missing")
|
|
178
|
+
elif not pathlib.Path(spec["config_file"]).is_file():
|
|
179
|
+
problems.append(f"agents.{name} template missing: {spec['config_file']}")
|
|
180
|
+
if problems:
|
|
181
|
+
fail(f"codex config additions: {'; '.join(problems)} ({target})")
|
|
182
|
+
info("codex config additions OK")
|
|
183
|
+
sys.exit(0)
|
|
184
|
+
|
|
185
|
+
def strip_managed(text):
|
|
186
|
+
out, skipping = [], False
|
|
187
|
+
for line in text.splitlines(keepends=True):
|
|
188
|
+
s = line.strip()
|
|
189
|
+
if s == BEGIN: skipping = True; continue
|
|
190
|
+
if s == END: skipping = False; continue
|
|
191
|
+
if skipping or s.endswith(TAG): continue
|
|
192
|
+
out.append(line)
|
|
193
|
+
return "".join(out)
|
|
194
|
+
|
|
195
|
+
if mode == "remove":
|
|
196
|
+
if not target.is_file():
|
|
197
|
+
sys.exit(0)
|
|
198
|
+
stripped = strip_managed(live_text)
|
|
199
|
+
if stripped == live_text:
|
|
200
|
+
info(f"no agent-bios additions in {target}")
|
|
201
|
+
sys.exit(0)
|
|
202
|
+
try:
|
|
203
|
+
tomllib.loads(stripped)
|
|
204
|
+
except Exception as exc:
|
|
205
|
+
fail(f"refusing removal; result would not parse: {exc}")
|
|
206
|
+
if dry:
|
|
207
|
+
info(f"[dry-run] remove agent-bios additions from {target}")
|
|
208
|
+
sys.exit(0)
|
|
209
|
+
backup = target.with_name(target.name + ".bak-agent-bios-uninstall")
|
|
210
|
+
backup.write_text(live_text)
|
|
211
|
+
target.write_text(stripped)
|
|
212
|
+
info(f"removed additions {target} (backup: {backup.name})")
|
|
213
|
+
sys.exit(0)
|
|
214
|
+
|
|
215
|
+
# mode == merge
|
|
216
|
+
if state_ok():
|
|
217
|
+
info(f"unchanged {target} (additions present)")
|
|
218
|
+
sys.exit(0)
|
|
219
|
+
|
|
220
|
+
# A drifted [agents.<tier>] outside our markers would become a duplicate
|
|
221
|
+
# table if we appended ours; that conflict needs the user, not a clobber.
|
|
222
|
+
base = strip_managed(live_text)
|
|
223
|
+
base_data = tomllib.loads(base) if base.strip() else {}
|
|
224
|
+
clash = [name for name in want_agents if name in base_data.get("agents", {})]
|
|
225
|
+
if clash:
|
|
226
|
+
fail(
|
|
227
|
+
f"unmanaged [agents.{'/'.join(clash)}] with drifted content in {target}; "
|
|
228
|
+
"align or remove them, then rerun install"
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
block_lines = [BEGIN]
|
|
232
|
+
if "features" not in base_data:
|
|
233
|
+
block_lines += ["[features]", f"multi_agent = true {TAG}"]
|
|
234
|
+
for name, spec in want_agents.items():
|
|
235
|
+
block_lines += [
|
|
236
|
+
f"[agents.{name}]",
|
|
237
|
+
f'description = "{spec["description"]}"',
|
|
238
|
+
f'config_file = "{spec["config_file"]}"',
|
|
239
|
+
]
|
|
240
|
+
block_lines.append(END)
|
|
241
|
+
block = "\n".join(block_lines) + "\n"
|
|
242
|
+
|
|
243
|
+
new_text = base
|
|
244
|
+
if "features" in base_data:
|
|
245
|
+
if base_data["features"].get("multi_agent") is None:
|
|
246
|
+
lines = new_text.splitlines(keepends=True)
|
|
247
|
+
for i, line in enumerate(lines):
|
|
248
|
+
if line.strip() == "[features]":
|
|
249
|
+
lines.insert(i + 1, f"multi_agent = true {TAG}\n")
|
|
250
|
+
break
|
|
251
|
+
new_text = "".join(lines)
|
|
252
|
+
elif base_data["features"].get("multi_agent") is not True:
|
|
253
|
+
info(f"note: features.multi_agent explicitly set in {target}; leaving it")
|
|
254
|
+
if new_text and not new_text.endswith("\n"):
|
|
255
|
+
new_text += "\n"
|
|
256
|
+
new_text += ("\n" if new_text else "") + block
|
|
257
|
+
|
|
258
|
+
try:
|
|
259
|
+
tomllib.loads(new_text)
|
|
260
|
+
except Exception as exc:
|
|
261
|
+
fail(f"merge result would not parse; live config untouched ({exc})")
|
|
262
|
+
if dry:
|
|
263
|
+
info(f"[dry-run] merge agent-bios additions into {target}")
|
|
264
|
+
sys.exit(0)
|
|
265
|
+
if live_text and backup_root:
|
|
266
|
+
bpath = pathlib.Path(backup_root + str(target))
|
|
267
|
+
bpath.parent.mkdir(parents=True, exist_ok=True)
|
|
268
|
+
bpath.write_text(live_text)
|
|
269
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
270
|
+
target.write_text(new_text)
|
|
271
|
+
info(f"merged additions {target}")
|
|
272
|
+
PY
|
|
273
|
+
}
|
|
274
|
+
|
|
129
275
|
# ---- optional dependencies -----------------------------------------------
|
|
130
276
|
# Capabilities are optional: a missing one only degrades the review routes that
|
|
131
277
|
# need it. config/agent-launch.toml is the single source for both the command
|
|
@@ -255,9 +401,12 @@ cmd_install() {
|
|
|
255
401
|
log "Deploying agent-bios from $REPO"
|
|
256
402
|
deploy_file "$REPO/claude/CLAUDE.md" "$CLAUDE_DIR/CLAUDE.md"
|
|
257
403
|
deploy_glob "$REPO/claude/guides" "*.md" "$CLAUDE_DIR/guides"
|
|
404
|
+
deploy_glob "$REPO/claude/agents" "*.md" "$CLAUDE_DIR/agents"
|
|
405
|
+
deploy_glob "$REPO/claude/hooks" "*.py" "$CLAUDE_DIR/hooks" "+x"
|
|
258
406
|
deploy_file "$REPO/codex/AGENTS.md" "$CODEX_DIR/AGENTS.md"
|
|
259
407
|
deploy_glob "$REPO/codex/guides" "*.md" "$CODEX_DIR/guides"
|
|
260
408
|
deploy_glob "$REPO/codex/agents" "*.toml" "$CODEX_DIR/agents"
|
|
409
|
+
codex_config_additions merge || exit 1
|
|
261
410
|
deploy_file "$REPO/scripts/codex-run.sh" "$CODEX_DIR/bin/codex-run" "+x"
|
|
262
411
|
deploy_file "$REPO/scripts/codex-helm.sh" "$CODEX_DIR/bin/codex-helm" "+x"
|
|
263
412
|
migrate_user_presets || exit 1 # must precede the deploy below, which overwrites profiles.toml
|
|
@@ -275,12 +424,19 @@ cmd_install() {
|
|
|
275
424
|
|| log "warning: venv provisioning failed (numbered-prompt fallback applies)"
|
|
276
425
|
fi
|
|
277
426
|
add_zsh_hook
|
|
427
|
+
if python3 "$REPO/scripts/session-learning/learning-state.py" project --repo "$REPO" >/dev/null 2>&1; then
|
|
428
|
+
info "learning-status projected"
|
|
429
|
+
else
|
|
430
|
+
log "note: learning-status projection unavailable (versions.json/ledger missing?)"
|
|
431
|
+
fi
|
|
278
432
|
log ""
|
|
279
433
|
log "Verifying deployment..."
|
|
280
434
|
if cmd_verify; then
|
|
281
435
|
log ""
|
|
282
436
|
log "Done. Open a new shell (or: source \"$ZSHRC\") to activate the zero-arg launcher."
|
|
283
|
-
|
|
437
|
+
# An untouched backup dir means nothing was replaced; that healthy state
|
|
438
|
+
# must not become a nonzero exit under set -e.
|
|
439
|
+
{ [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ] && log "Replaced files were backed up under $BACKUP_DIR"; } || true
|
|
284
440
|
else
|
|
285
441
|
log "VERIFY FAILED after install — see messages above"
|
|
286
442
|
exit 1
|
|
@@ -298,6 +454,8 @@ cmd_verify() {
|
|
|
298
454
|
verify_match "$REPO/config/agent-launch.toml" "$LAUNCH_DIR/profiles.toml" || fail=1
|
|
299
455
|
verify_match "$REPO/shell/agent-launch.zsh" "$LAUNCH_DIR/shell.zsh" || fail=1
|
|
300
456
|
for gp in "$REPO"/claude/guides/*.md; do verify_present "$CLAUDE_DIR/guides/$(basename "$gp")" || fail=1; done
|
|
457
|
+
for gp in "$REPO"/claude/agents/*.md; do verify_present "$CLAUDE_DIR/agents/$(basename "$gp")" || fail=1; done
|
|
458
|
+
for gp in "$REPO"/claude/hooks/*.py; do verify_present "$CLAUDE_DIR/hooks/$(basename "$gp")" || fail=1; done
|
|
301
459
|
for gp in "$REPO"/codex/guides/*.md; do verify_present "$CODEX_DIR/guides/$(basename "$gp")" || fail=1; done
|
|
302
460
|
python3 - "$CODEX_DIR/agents" <<'PY' && info "agent TOMLs OK" || fail=1
|
|
303
461
|
import sys, pathlib, tomllib
|
|
@@ -308,6 +466,7 @@ assert not missing, f"missing agent TOMLs in {root}: {sorted(missing)}"
|
|
|
308
466
|
for p in sorted(root.glob("*.toml")):
|
|
309
467
|
tomllib.loads(p.read_text())
|
|
310
468
|
PY
|
|
469
|
+
codex_config_additions check || fail=1
|
|
311
470
|
if command -v codex >/dev/null 2>&1 && [ -x "$CODEX_DIR/bin/codex-helm" ]; then
|
|
312
471
|
if "$CODEX_DIR/bin/codex-helm" --dry-run --mode review "probe" >/dev/null 2>&1; then
|
|
313
472
|
info "codex-helm dry-run OK"
|
|
@@ -340,6 +499,7 @@ PY
|
|
|
340
499
|
|
|
341
500
|
cmd_uninstall() {
|
|
342
501
|
migrate_state
|
|
502
|
+
codex_config_additions remove || log "warning: could not remove codex config additions"
|
|
343
503
|
if [ -f "$MANIFEST" ]; then
|
|
344
504
|
local f
|
|
345
505
|
while IFS= read -r f; do
|
|
@@ -357,7 +517,7 @@ cmd_uninstall() {
|
|
|
357
517
|
done
|
|
358
518
|
fi
|
|
359
519
|
local d
|
|
360
|
-
for d in "$CLAUDE_DIR/guides" "$CODEX_DIR/guides" "$CODEX_DIR/agents" "$CODEX_DIR/bin" "$LAUNCH_DIR"; do
|
|
520
|
+
for d in "$CLAUDE_DIR/guides" "$CLAUDE_DIR/agents" "$CODEX_DIR/guides" "$CODEX_DIR/agents" "$CODEX_DIR/bin" "$LAUNCH_DIR"; do
|
|
361
521
|
[ -d "$d" ] && rmdir "$d" 2>/dev/null && info "removed empty $d" || true
|
|
362
522
|
done
|
|
363
523
|
remove_zsh_hook
|