fix(adapters): grant claude-code write permissions + fail on zero-file completion (#739) - #818
Conversation
…e completion (#739) --print mode silently denies Edit/Write/Bash, so the default ClaudeCodeAdapter (no allowlist) could only analyze, never modify — and P0.5 gates-on-unchanged-tree then marked tasks COMPLETED with zero code written. - ClaudeCodeAdapter default now passes --permission-mode bypassPermissions (acceptEdits alone leaves Bash denied); explicit allowlist path unchanged. - SubprocessAdapter gains opt-in require_file_changes (default False, so codex/opencode + plumbing tests are unaffected); ClaudeCodeAdapter defaults it True. A run that exits 0 but modifies no files is downgraded to failed.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
WalkthroughClaudeCodeAdapter now accepts a ChangesPermission defaults and file-change enforcement
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related issues
Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Review: fix(adapters): grant claude-code write permissions + fail on zero-file completion (#739)This is a well-scoped fix for a real bug (COMPLETED tasks with zero code written), and both halves of the change are covered by targeted new tests. No prior CodeRabbit review has posted yet (it hit a rate limit), so this is the first substantive review on the PR — no earlier comments to reconcile with. Findings1. 2. Zero-file detection failures and zero-file truth are indistinguishable (correctness edge case) 3. Other notes
Nothing here should block merging; (1) and (2) are the ones I'd actually want a follow-up ticket for. |
…review) Third-party (codex) review flagged that require_file_changes judged work solely by `git diff HEAD`. With bypassPermissions now allowing Bash, an agent that commits its own work leaves an empty diff, and a non-git workspace can never show changes — both would spuriously downgrade a successful run to failed. The guard now only fires when it can positively confirm no work: a resolvable git repo whose HEAD did not advance during the run AND whose tree has no changes. Captures a pre-run HEAD baseline; a moved HEAD (self-commit) or unresolvable HEAD (non-git/unborn) is treated as 'cannot fail'. Verified end-to-end against a real git repo for all four cases.
Third-party review (codex, GLM/opencode timed out)Ran [High → fixed] Resolution: the guard now captures a pre-run HEAD baseline and only fires when it can positively confirm no work — a resolvable git repo whose HEAD did not advance AND whose tree has no changes. A moved HEAD (self-commit) or unresolvable HEAD (non-git/unborn) is treated as "cannot fail". Verified end-to-end against a real git repo:
No codex/opencode adapter regression (their |
|
Re-review: fix(adapters): grant claude-code write permissions + fail on zero-file completion (#739) This is a follow-up review of the updated diff (commit Findings
Already-noted, still open (no new action needed here)
Test coverage for the new HEAD-baseline logic is solid (empty-diff-but-committed, non-git-workspace, and the original zero-file/opt-out cases are all exercised at both |
…e-review) Internal re-review: a transient pre-run _git_head failure (head_before=None) plus a successful post-run read made 'committed' true via 'None != sha', silently reopening the false-completion hole. Require head_before is not None so an unknown baseline can't fake a commit; bias toward failing loudly.
|
Triaged internal-review findings. Addressed now: the re-review's HEAD-baseline false-pass hardening (commit |
Re-review: fix(adapters): grant claude-code write permissions + fail on zero-file completion (#739)Third pass, covering the latest commit ( Verified fix is correct.
All four are directly exercised by the new tests ( One residual asymmetry, not a regression, worth being aware of: because Everything else already triaged. The three other advisory findings from my previous reviews ( No blocking issues. This is ready to merge as far as the adapter logic goes. |
Re-review: fix(adapters): grant claude-code write permissions + fail on zero-file completion (#739)Checked the current head against my last re-review (commit No new findings. Standing position unchanged: no blocking issues, ready to merge as far as the adapter logic goes. The four advisory items from my earlier passes ( |
…sions (#819) Closes #819. Four follow-ups from the #739 / PR #818 review. 1. Dangerous-command guard for bypassPermissions (security). The built-in ReAct engine filters every Bash command through is_dangerous_command(); the delegated claude CLI had unrestricted Bash with no CodeFrame-side equivalent, and #565 turns externally-authored issue bodies into task prompts. Registers a PreToolUse hook (hooks fire even under bypassPermissions) reusing is_dangerous_command verbatim, so both engines block the same set from one source of truth. Patterns live in a stdlib-only leaf (core/dangerous_commands.py) and the guard outside the eagerly-importing adapters package, keeping the per-Bash-call hook cost at ~142ms rather than ~423ms. 2. Exit-0 clarifications route to a blocker instead of a hard failure. --print cannot prompt, so a genuine ambiguity is printed and the process exits clean; the zero-file guard hard-failed it with a misleading "likely lacked write permission". Tactical questions still fail, by design. 3. require_file_changes follows what the allowlist grants, not whether one was passed. An unrecognized tool is assumed write-capable so the unknown case fails loudly rather than silently disabling the #739 guard. 4. Git errors are logged; empty now means failed, so a transient hiccup was indistinguishable from "the agent changed nothing". Verified: guard proven live against the real claude CLI (denied dd if=/dev/zero of=/dev/null, allowed echo); 4275 tests pass; ruff clean; diff coverage 96.67%; test-mutation check passes on all 5 new behaviors; codex cross-family review (pre-PR + posted post-PR) and the GLM bug-hunter both found no defects. Known limitation: the guard is advisory-grade, not a sandbox — a regex matcher an agent that means to evade it can evade, same grade as ReAct's.
Closes #739
Problem
ClaudeCodeAdapterbuilt["--print"]with no permission config. In non-interactive--printmode Claude Code auto-denies Edit/Write/Bash, so the delegated agent could analyzebut never modify files. Combined with P0.5's gates-on-unchanged-tree, tasks were marked
COMPLETED with zero code written — the exact failure the audit flagged.
Fix
1. Permission config (
claude_code.py)Default path (no allowlist — the only production caller) now appends
--permission-mode bypassPermissions, so Edit/Write/Bash are auto-approved in--printmode.Chose
bypassPermissionsover theacceptEditsexample in the issue becauseacceptEditsalone still leaves Bash denied. The explicit-
allowlistAPI path is unchanged.2. Zero-modified-files hard error (
subprocess_adapter.py)Base
SubprocessAdaptergains an opt-inrequire_file_changesflag (default False, socodex/opencode and all plumbing tests are unaffected).
ClaudeCodeAdapterdefaults it True:a run that exits 0 but modifies no files is downgraded
completed → failedwith a clear error,so downstream gates can no longer pass on an unchanged tree.
Acceptance criteria
Verification
claude --print --permission-mode bypassPermissions— accepted by the real CLI (claude --helpconfirms the flag/mode).require_file_changes=Trueguard exercised in unit tests (zero-file →failed, files-changed →completed); opt-out restores plain exit-code mapping.tests/coresuite 2380 passed; adapters+registry 151 green;ruff checkclean.Known limitations
bypassPermissionsgrants full Bash to the delegated agent — appropriate for an autonomouscoder running in the workspace, matching the built-in ReAct engine's tool access.
require_file_changesis enabled only forclaude-code; codex/opencode keep exit-codemapping until a false-completion is observed there (default-off flag, opt-in later).
Summary by CodeRabbit
New Features
Bug Fixes