mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-09 16:02:36 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The `claude_local` adapter runs Claude through the ACP engine (claude-agent-acp) inside remote sandboxes > - Paperclip seeds the sandbox Claude settings with `permissions.defaultMode: "default"`, so Claude asks acpx for permission before every MCP call and every Bash call that is not read-only > - In the default `approve-all` mode, acpx approves every request. The permission round trip gives no access control, but it is the step where tool calls stall > - Intermittently, the Claude CLI never sends that permission request. The call stays `pending` until the 30-minute stalled-tool watchdog ends the turn (`acpx_tool_stalled`) > - This pull request starts approve-all sandbox sessions in `bypassPermissions`, so Claude does not use the permission round trip at all > - The benefit is that sandbox runs no longer lose about 35 minutes per stall, and `approve-reads` and `deny-all` agents keep their current permission behavior ## Linked Issues or Issue Description Refs #16688 Refs #16769 **What happened?** Sandbox `claude_local` ACP runs ended with `acpx_tool_stalled`: "A pending tool call (kind other) received no update for 30 minutes, so the run ended the turn instead of waiting for the execution timeout." The diagnostics from #16688 and #16769 show the shape. The stalled call got its `pending` update and its input updates. Then its permission request never reached acpx. Finished calls of the same kind in the same run did send a request. The stall occurred on MCP calls and on Bash calls, in the main agent and in background subagents. Calls that need no permission (ToolSearch, read-only Bash) never stalled. **Expected behavior** In `approve-all` mode, a tool call must not wait on a permission round trip that acpx always approves. **Steps to reproduce** 1. Run a `claude_local` agent with the ACP engine on a sandbox target, with the default `approve-all` permission mode. 2. Make many MCP or network Bash calls during the turn. 3. Sometimes a call stays `pending` with no permission request. The watchdog then ends the turn after 30 minutes. **Agent adapter(s) involved** Claude Code (`claude_local`, ACP engine, sandbox target). ## What Changed - `claude-config.ts`: `prepareClaudeConfigSeed` accepts `permissionDefaultMode` (`"default"` or `"bypassPermissions"`). The sanitized seed writes that value into `permissions.defaultMode`. In bypass mode the seed writes `settings.json` also when the host has no `settings.json`. Hooks, MCP servers and host permission rules are still removed. - `claude-config.ts`: `overrideRemoteClaudeLocalPermissionMode` sets `bypassPermissions` in the **sandbox copy** of the workspace `.claude/settings.local.json`. The engine writes that file with `defaultMode: "default"`, and the local tier overrides the user seed. Before workspace copy-back, the override is reset in the sandbox, so copy-back never treats it as an agent edit. After copy-back, if the host file still has `bypassPermissions`, only `defaultMode` is put back. Host and agent edits to other settings are kept. - `acp.ts`: the sandbox managed-home seam reads the run's effective ACPX permission mode. If the mode is `approve-all`, the seam seeds `bypassPermissions`, applies the workspace override above, and sets `IS_SANDBOX=1` through the existing `claudeSandboxPermissionEnv` helper. This lets the bypass apply when the sandbox user is root, the same rule as the CLI lane. The mode resolution is the same as the engine's: an absent value or `"default"` becomes `approve-all`. An unrecognized value keeps `"default"`. - These keep `defaultMode: "default"` and do not change: `approve-reads`, `deny-all`, the CLI lane, the Test probes, managed AI connections, and an operator `CLAUDE_CONFIG_DIR`. - Tests: two seed tests in `claude-config.test.ts`. In `acp.test.ts`: an end-to-end executor test for five permission modes (absent, `approve-all`, `default`, `approve-reads`, `deny-all`) that checks the mode Claude actually gets during the turn and that the host settings keep `default`, and a test that host and agent edits to the workspace settings survive copy-back without `bypassPermissions`. ## Verification - `pnpm exec vitest run packages/adapters/claude-local`: 393 passed, 1 skipped (before the copy-back commits); full CI is green on the current head. - Regression proof: with the new tests and the old `acp.ts` and `claude-config.ts`, the seed tests and the absent, `approve-all` and `default` cases fail (`expected 'default' to be 'bypassPermissions'`). The `approve-reads` and `deny-all` cases pass on both versions, because their behavior does not change. - `pnpm exec tsc --noEmit` in `packages/adapters/claude-local`: clean. ## Risks - Behavior change for sandbox `claude_local` ACP runs in `approve-all` mode (the default): Claude does not ask permission for tools. Paperclip already approves every request in this mode, so the access outcome does not change. Claude's bypass-immune safety checks still go through `canUseTool`. - The seed directory is content-addressed, so the bypass seed and the default seed are different snapshots and do not overwrite each other. - Agents that set `approve-reads` or `deny-all` keep the permission round trip. The stall can still occur for them. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, with tool use and code execution in an agent harness. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>