Skip to content

Commit 7eedcdc

Browse files
authored
fix: use absolute paths in --allowedTools for sensitive file editing (Refs: beans-huwr) (#166)
## Summary - Agent sessions in act mode were still getting permission prompts when editing `.claude/rules/*` and `CLAUDE.md` files, despite the fix in #164 - **Root cause:** `--allowedTools` patterns used relative globs (e.g. `Edit(.claude/**)`) but Claude Code's Edit/Write tools operate on absolute file paths, so the patterns never matched - Fix: construct patterns using `session.WorkDir` (e.g. `Edit(/path/to/workdir/.claude/**)`) and pass each with its own `--allowedTools` flag ## Test plan - [ ] `mise build` and spawn an agent in act mode via Beans UI - [ ] Have it edit a `.claude/rules/*.md` file — should succeed without permission prompts - [ ] Verify `mise test` passes
1 parent 8999234 commit 7eedcdc

3 files changed

Lines changed: 42 additions & 32 deletions

File tree

.beans/beans-huwr--agent-sessions-fail-to-edit-claude-config-files-cl.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,20 @@
33
title: Agent sessions fail to edit Claude config files (.claude/rules, CLAUDE.md)
44
status: in-progress
55
type: bug
6+
priority: normal
67
created_at: 2026-03-20T14:46:47Z
7-
updated_at: 2026-03-20T14:46:47Z
8+
updated_at: 2026-03-20T15:17:40Z
89
---
910

1011
When a Beans UI agent (running with --dangerously-skip-permissions) tries to write to .claude/rules/*.md or CLAUDE.md, Claude Code still blocks the write because it considers these 'sensitive files (project rules)'. The agent asks the user to approve the permission, but there's no way to grant it in non-interactive mode. Fix: add --allowedTools entries for Edit and Write on these sensitive file paths.
12+
13+
## Root Cause
14+
15+
The initial fix (commit 7a43a18) used relative path patterns like `Edit(.claude/**)` in `--allowedTools`, but Claude Code's Edit/Write tools operate on **absolute file paths**. The glob `.claude/**` never matched because the tool calls use paths like `/full/path/to/workdir/.claude/rules/frontend.md`.
16+
17+
Additionally, the patterns were passed as multiple values after a single `--allowedTools` flag, which could cause variadic argument parsing issues.
18+
19+
## Fix
20+
21+
- Use absolute paths based on `session.WorkDir` (e.g., `Edit(/path/to/workdir/.claude/**)`)
22+
- Pass each pattern with its own `--allowedTools` flag to avoid variadic parsing ambiguity

internal/agent/claude.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -820,10 +820,17 @@ func buildClaudeArgs(session *Session) []string {
820820
args = append(args, "--dangerously-skip-permissions")
821821
// Explicitly allow editing Claude's own config files, which are
822822
// classified as "sensitive" and blocked even with --dangerously-skip-permissions.
823-
args = append(args, "--allowedTools",
824-
"Edit(CLAUDE.md)", "Write(CLAUDE.md)",
825-
"Edit(.claude/**)", "Write(.claude/**)",
826-
)
823+
// Patterns must use absolute paths because Claude Code's Edit/Write tools
824+
// operate on absolute file paths internally.
825+
if session.WorkDir != "" {
826+
dir := session.WorkDir
827+
args = append(args,
828+
"--allowedTools", "Edit("+dir+"/CLAUDE.md)",
829+
"--allowedTools", "Write("+dir+"/CLAUDE.md)",
830+
"--allowedTools", "Edit("+dir+"/.claude/**)",
831+
"--allowedTools", "Write("+dir+"/.claude/**)",
832+
)
833+
}
827834
} else if session.PlanMode {
828835
args = append(args, "--permission-mode", "plan")
829836
}

internal/agent/manager_test.go

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ func TestSetActMode_IncludedInSnapshot(t *testing.T) {
770770
}
771771

772772
func TestBuildClaudeArgs_ActMode(t *testing.T) {
773-
args := buildClaudeArgs(&Session{ActMode: true})
773+
args := buildClaudeArgs(&Session{ActMode: true, WorkDir: "/tmp/test-project"})
774774
found := false
775775
for _, a := range args {
776776
if a == "--dangerously-skip-permissions" {
@@ -782,34 +782,25 @@ func TestBuildClaudeArgs_ActMode(t *testing.T) {
782782
t.Errorf("expected --dangerously-skip-permissions in args, got %v", args)
783783
}
784784

785-
// Act mode should also include --allowedTools for sensitive Claude config files
786-
foundAllowed := false
787-
for i, a := range args {
788-
if a == "--allowedTools" {
789-
foundAllowed = true
790-
// Verify the expected tool patterns follow
791-
remaining := args[i+1:]
792-
expected := []string{
793-
"Edit(CLAUDE.md)", "Write(CLAUDE.md)",
794-
"Edit(.claude/**)", "Write(.claude/**)",
795-
}
796-
for _, e := range expected {
797-
found := false
798-
for _, r := range remaining {
799-
if r == e {
800-
found = true
801-
break
802-
}
803-
}
804-
if !found {
805-
t.Errorf("expected %q in --allowedTools args, got %v", e, remaining)
806-
}
785+
// Act mode should include --allowedTools with absolute paths for sensitive Claude config files.
786+
// Each pattern must be preceded by its own --allowedTools flag.
787+
expected := []string{
788+
"Edit(/tmp/test-project/CLAUDE.md)",
789+
"Write(/tmp/test-project/CLAUDE.md)",
790+
"Edit(/tmp/test-project/.claude/**)",
791+
"Write(/tmp/test-project/.claude/**)",
792+
}
793+
for _, e := range expected {
794+
found := false
795+
for i, a := range args {
796+
if a == "--allowedTools" && i+1 < len(args) && args[i+1] == e {
797+
found = true
798+
break
807799
}
808-
break
809800
}
810-
}
811-
if !foundAllowed {
812-
t.Errorf("expected --allowedTools in act mode args, got %v", args)
801+
if !found {
802+
t.Errorf("expected --allowedTools %q in args, got %v", e, args)
803+
}
813804
}
814805
}
815806

0 commit comments

Comments
 (0)