This repository has been archived on 2026-09-17. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
nixos-config/agents/claude-settings/builder.json
pijukka 035c869433 agent-codex(builder): migrate Builder role from Codex to Claude Code
Codex hit its weekly usage_limit_exceeded quota (verified via the
session's own JSONL error event, reset not until the next day) and
blocked a real board-triggered job. Rather than wait, migrate the
Builder role's model backend from `codex exec` to `claude -p`
(Claude Code, headless) -- Reviewer/Agent stay on Codex, untouched.

- builder.py: run_codex() -> run_claude(). Same contract (atomic
  session, iteration limit, ===COMMIT-MESSAGE=== handoff, stash-based
  foreign-change isolation) -- only the actual subprocess invocation
  changes. Deliberately no HOME/CLAUDE_CONFIG_DIR override: the Builder
  shares the interactive drone user's own Claude Code login/quota
  instead of a dedicated identity, an explicit tradeoff (no second
  Claude subscription for this role, but the Builder now competes for
  the same 5h/7-day usage windows as interactive use).
- common.py: additive run_claude_streaming()/parse_claude_events()/
  build_claude_partial_response()/append_claude_model_options()
  alongside (not replacing) the existing Codex-shaped helpers, which
  agent-codex/worker.py's Agent role still needs unchanged.
- agents/claude-settings/builder.json (new): permission-based
  equivalent of Codex's --sandbox workspace-write -- installed
  read-only into the nix store (not read live from the checkout,
  which is one of the Builder's own writable dirs) so a job can never
  loosen its own deny-list for the next run. Denies git commit/push,
  nix build/flake check, sudo/ssh/agenix/deploy scripts, .git/ writes.
- agent-codex.nix: new AGENT_BUILDER_CLAUDE_* env vars, nix-store
  install of the settings file, and ReadWritePaths += /home/drone/.claude
  (ProtectHome=read-only otherwise blocks Claude's own session/cache
  state, a deliberate, minimal loosening tied to the identity decision
  above).

Found and fixed live during validation (not caught by unit tests,
which mock the subprocess): a bare `Edit(**)`/`Write(**)`/`Read(**)`
permission pattern only matches paths under the process's own cwd
(AGENT_ROLE_DIR, i.e. agents/) -- it silently never matched any of the
actual writable directories, which are only reachable via --add-dir.
First live board job came back "no_changes" because every Edit/Write
attempt was denied. Fixed with absolute-path patterns (`Edit(//**)`
etc.) plus `--setting-sources ""` to isolate from this checkout's own
ambient .claude/settings(.local).json. Verified live end-to-end after
the fix: a real board job edited a file, the wrapper's own scoped
flake-check/build ran, and it committed+pushed cleanly (`a971216`) --
2 iterations, well under the limit, no resource spike.

76/76 unit tests pass (test_agent_codex.py); agents/tests/roles.sh
(separate from nix flake check) updated for the resulting builder
catalog version bump (1.1.0 -> 1.2.0, Minor: effective permissions are
unchanged, only the enforcement mechanism's name changes from
"workspace-write" to "scoped-write") and passes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015cLYfA14n3kMmnhA8n1QG4
2026-09-06 22:49:54 +02:00

32 lines
686 B
JSON

{
"permissions": {
"defaultMode": "dontAsk",
"allow": [
"Read(//**)",
"Glob(//**)",
"Grep(//**)",
"Edit(//**)",
"Write(//**)",
"Bash(git status *)",
"Bash(git diff *)",
"Bash(git add *)",
"Bash(git log *)",
"Bash(git show *)",
"Bash(git ls-remote *)",
"Bash(git fetch *)"
],
"deny": [
"Bash(git commit *)",
"Bash(git push *)",
"Bash(sudo *)",
"Bash(nixos-rebuild *)",
"Bash(nix build *)",
"Bash(nix flake check *)",
"Bash(ssh *)",
"Bash(agenix *)",
"Bash(scripts/deploy-pinix.sh *)",
"Edit(.git/**)",
"Write(.git/**)"
]
}
}