diff --git a/.claude/settings.global.json b/.claude/settings.global.json new file mode 100644 index 0000000..6e7e16a --- /dev/null +++ b/.claude/settings.global.json @@ -0,0 +1,16 @@ +{ + "permissions": { + "allow": [ + "mcp__atlassian__getJiraIssue" + ], + "defaultMode": "auto" + }, + "worktree": { + "baseRef": "head" + }, + "statusLine": { + "type": "command", + "command": "bash ~/.claude/statusline-command.sh" + }, + "editorMode": "vim" +} diff --git a/.claude/settings.json b/.claude/settings.json index e4c7604..e06b033 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,19 +1,4 @@ { - "permissions": { - "allow": [ - "mcp__atlassian__getJiraIssue" - ], - "defaultMode": "auto" - }, - "worktree": { - "baseRef": "head" - }, - "statusLine": { - "type": "command", - "command": "bash ~/.claude/statusline-command.sh" - }, - "editorMode": "vim", - "model": "opus", "hooks": { "SessionStart": [ { diff --git a/link-agents.sh b/link-agents.sh index 7c6ad22..5a49bf9 100755 --- a/link-agents.sh +++ b/link-agents.sh @@ -33,7 +33,11 @@ link_skills_into() { # --- Claude Code ----------------------------------------------------------- mkdir -p "$HOME/.claude" -ln $LN_OPTS "$SCRIPT_DIR/.claude/settings.json" "$HOME/.claude/settings.json" +# User-scope settings come from settings.global.json. The sibling +# settings.json holds the dotfiles repo's SessionStart bootstrap hook and +# is read only as *project* settings when working in this repo -- linking +# it at user scope would fire that project-relative hook in every project. +ln $LN_OPTS "$SCRIPT_DIR/.claude/settings.global.json" "$HOME/.claude/settings.json" ln $LN_OPTS "$SCRIPT_DIR/.claude/statusline-command.sh" "$HOME/.claude/statusline-command.sh" ln $LN_OPTS "$SCRIPT_DIR/.claude/CLAUDE.md" "$HOME/.claude/CLAUDE.md" link_skills_into "$HOME/.claude/skills" diff --git a/tests/link-agents.bats b/tests/link-agents.bats index de4c65c..e65c869 100644 --- a/tests/link-agents.bats +++ b/tests/link-agents.bats @@ -19,11 +19,21 @@ teardown() { [ -L "$HOME/.claude/statusline-command.sh" ] [ -L "$HOME/.claude/CLAUDE.md" ] - # Each link should resolve to a real file inside the repo copy. - [ "$(readlink "$HOME/.claude/settings.json")" = "$SANDBOX_REPO/.claude/settings.json" ] + # Each link should resolve to a real file inside the repo copy. The + # user-scope settings come from settings.global.json, NOT the dotfiles + # project settings.json (which carries the repo-only bootstrap hook). + [ "$(readlink "$HOME/.claude/settings.json")" = "$SANDBOX_REPO/.claude/settings.global.json" ] [ "$(readlink "$HOME/.claude/CLAUDE.md")" = "$SANDBOX_REPO/.claude/CLAUDE.md" ] } +@test "global settings carry no project-relative hook; project settings do" { + # The user-scope file must not reference \$CLAUDE_PROJECT_DIR, or its + # hooks would fire (and error) in every project. The project file is + # where the SessionStart bootstrap hook belongs. + ! grep -q 'CLAUDE_PROJECT_DIR' "$PROJECT_ROOT/.claude/settings.global.json" + grep -q 'session-start.sh' "$PROJECT_ROOT/.claude/settings.json" +} + @test "links every skill folder under .agent/skills/" { # Add a synthetic skill alongside whatever real skills exist. mkdir -p "$SANDBOX_REPO/.agent/skills/synthetic-skill"