[BUG] add_dirs Grants Filesystem Access to Read/Write Tools but Not to Bash Tool
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
The add_dirs option in ClaudeAgentOptions is intended to grant the agent read/write access to specified directories beyond the current working directory (cwd). This works correctly for the dedicated file tools (Read, Write, Edit, etc.), which can successfully access files in the added directories using the original host paths.
However, the Bash tool does not have equivalent access. Attempts to read from or write to files in the added directories via bash commands fail, typically with "Read-only file system" errors (for writes) or "No such file or directory" (for reads/writes).
This inconsistency limits workflows that combine file tools with shell commands (e.g., using tools like uv that rely on cache directories).
Observation (Potential Clue)
When the agent is asked why a Bash operation is failing (e.g., "why did that command fail with read-only file system?"), it reveals details from its system prompt, including the sandbox's write.allowOnly configuration. This lists added directories under the home path with a /tmp prefix prepended:
JSON
"write": {
"allowOnly": [
...,
"/tmp/home/kfrance/.cache/uv"
]
}
This indicates possible internal path remapping or bind-mounting for sandbox isolation. The dedicated file tools appear to handle any such translation transparently, while Bash does not. It is unclear if this remapping is the direct cause, but it correlates strongly with the issue.
The documentation for add_dirs does not mention differences in how permissions apply to Bash vs. file tools, nor any path remapping behavior.
What Should Happen?
he add_dirs feature should provide consistent filesystem access across all tools, including Bash. Bash commands using the original host paths should succeed identically to the dedicated file tools.
If consistency is not feasible due to sandbox constraints:
The documentation should explicitly describe any limitations, differences in tool behavior, or path remapping rules.
If remapping occurs, provide guidance on constructing correct paths for Bash (e.g., using the /tmp/... prefix).
Currently, the undocumented discrepancy and reliance on querying the agent for internal details make add_dirs unreliable and confusing for mixed-tool workflows.
Error Messages/Logs
Read only file system errors for bash commands.
Steps to Reproduce
Ensure a directory exists under the home path, e.g., ~/.cache/uv.
Initialize the SDK session with add_dirs including that directory:
python
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from pathlib import Path
uv_cache_dir = Path.home() / ".cache" / "uv"
options = ClaudeAgentOptions(
cwd=worktree_path, # any valid cwd
model="opus",
settings=str(sdk_settings_path),
permission_mode="acceptEdits",
add_dirs=[uv_cache_dir], # Intended to allow access to ~/.cache/uv
)
In an agent interaction, use the Write tool on a file in the added directory (using the original host path):
text
Write(file_path="/home/kfrance/.cache/uv/test.txt", content="test")
→ Succeeds (file is created on the host filesystem).
In the same or subsequent interaction, use the Bash tool to access the same file/path:
echo "test" > /home/kfrance/.cache/uv/test.txt
or
text
cat /home/kfrance/.cache/uv/test.txt
→ Fails (typically "Read-only file system" for writes; may vary for reads).
Ask the agent about the failure (e.g., "Why did that bash command fail?"). It will reference the sandbox configuration from its system prompt, revealing the /tmp-prefixed path in write.allowOnly.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.0.76 (Claude Code)
Platform
Anthropic API
Operating System
Other Linux
Terminal/Shell
Other
Additional Information
_No response_
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗