Skip to content

crow-workspace: scaffold baseline allow list into each worktree's .claude/settings.local.json #247

@dhilgaertner

Description

@dhilgaertner

Problem

Every Claude Code session kicked off by /crow-workspace (and /crow-batch-workspace) lands in a fresh worktree directory and immediately starts prompting the user to approve common, low-risk commands that the prompt template itself instructs the session to run. Examples observed during a single session:

  • Bash(gh issue view <url> --comments)
  • Bash(gh issue view <number> --repo <owner/repo> --comments)
  • Bash(gh issue view ... 2>&1 | tee /tmp/claude/issue415.txt)
  • Output redirection variants (> /tmp/claude/..., tee ...)

Each prompt requires manual approval, which:

  1. Defeats the purpose of auto-launched sessions. The prompt template explicitly tells the session to call gh issue view ... as step 1. The user has already implicitly authorized it by invoking /crow-workspace.
  2. Multiplies friction in batch mode. With /crow-batch-workspace running 3–5 sessions in parallel, the user has to context-switch to each tab to approve the same commands.
  3. Has no analog in the Manager session, which already has a comprehensive allow list at /Users/dustinhilgaertner/Dev2/.claude/settings.json (the dev root .claude/settings.json). Worktree sessions don't inherit this — they're rooted under {devRoot}/{workspace}/{repo}-{n}-{slug}/, and Claude Code only reads settings from the worktree (and ancestors) at launch time.

Root Cause

setup.sh creates the worktree, registers the session, writes the prompt file, and launches Claude Code — but it does not drop a .claude/settings.local.json (or equivalent) into the worktree with a baseline allow list. So the worktree session inherits whatever the repo itself ships (often nothing relevant) and prompts for everything.

Proposal

Scaffold a baseline .claude/settings.local.json into each worktree as part of setup.sh, before launching Claude Code. The contents should mirror the Manager's tested allow list, scoped to the kinds of commands the crow prompt template instructs sessions to run.

Suggested baseline allow list

{
  "permissions": {
    "allow": [
      // Ticket / PR inspection (the prompt template runs these on step 1)
      "Bash(gh issue view:*)",
      "Bash(gh issue list:*)",
      "Bash(gh issue edit:*)",
      "Bash(gh pr view:*)",
      "Bash(gh pr list:*)",
      "Bash(gh pr diff:*)",
      "Bash(gh pr checks:*)",
      "Bash(gh pr create:*)",
      "Bash(gh pr edit:*)",
      "Bash(gh pr review:*)",
      "Bash(gh pr comment:*)",
      "Bash(gh repo view:*)",
      "Bash(gh api graphql:*)",
      "Bash(gh api repos:*)",
      "Bash(gh auth status:*)",
      "Bash(gh search:*)",

      // GitLab equivalents
      "Bash(GITLAB_HOST=* glab issue view:*)",
      "Bash(GITLAB_HOST=* glab mr view:*)",
      "Bash(GITLAB_HOST=* glab mr list:*)",
      "Bash(GITLAB_HOST=* glab mr create:*)",
      "Bash(GITLAB_HOST=* glab auth status:*)",
      "Bash(glab issue view:*)",
      "Bash(glab mr view:*)",
      "Bash(glab mr list:*)",

      // Git operations a feature branch needs
      "Bash(git status:*)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Bash(git show:*)",
      "Bash(git fetch:*)",
      "Bash(git pull:*)",
      "Bash(git push:*)",
      "Bash(git add:*)",
      "Bash(git commit:*)",
      "Bash(git checkout:*)",
      "Bash(git branch:*)",
      "Bash(git stash:*)",
      "Bash(git rebase:*)",
      "Bash(git merge:*)",
      "Bash(git -C:*)",
      "Bash(git ls-remote:*)",
      "Bash(git worktree:*)",

      // Shell utilities the agent reaches for constantly
      "Bash(cat:*)",
      "Bash(cat >:*)",
      "Bash(head:*)",
      "Bash(tail:*)",
      "Bash(grep:*)",
      "Bash(rg:*)",
      "Bash(ls:*)",
      "Bash(find:*)",
      "Bash(which:*)",
      "Bash(which -a:*)",
      "Bash(sleep:*)",
      "Bash(mkdir -p:*)",
      "Bash(tee:*)",
      "Bash(wc:*)",
      "Bash(jq:*)",

      // Output redirection to scratch space
      "Bash(* > $TMPDIR/*)",
      "Bash(* > /tmp/claude/*)",
      "Bash(* | tee $TMPDIR/*)",
      "Bash(* | tee /tmp/claude/*)",

      // crow CLI (sessions sometimes self-introspect)
      "Bash(crow get-session:*)",
      "Bash(crow list-worktrees:*)",
      "Bash(crow list-links:*)",
      "Bash(crow set-status:*)",

      // First-party Claude Code tools
      "Read",
      "Write",
      "Edit",
      "Glob",
      "Grep"
    ]
  }
}

Implementation sketch

In setup.sh, after setup_worktree and before launch_claude:

write_session_settings() {
  local settings_dir="$WORKTREE_PATH/.claude"
  local settings_path="$settings_dir/settings.local.json"
  mkdir -p "$settings_dir"

  # Don't clobber an existing settings.local.json (e.g. checked in by the repo)
  if [[ -f "$settings_path" ]]; then
    log "settings.local.json already exists, leaving untouched"
    return
  fi

  # Source the baseline from a versioned template under the skill
  cp "$SCRIPT_DIR/session-settings.template.json" "$settings_path"
  log "Wrote baseline allow list to $settings_path"
}

The template lives next to setup.sh so it's editable in one place and version-controlled.

Open questions / things to bikeshed

  • Location: .claude/settings.local.json (gitignored by Claude Code's defaults) is the right choice — won't get committed by accident. Confirm Claude Code reads it.
  • Merge vs. overwrite: if the repo already has a .claude/settings.json with its own allow list, the worktree's settings.local.json will be merged on top. Verify the precedence works in our favor.
  • Per-repo overrides: some repos might want different defaults (e.g. corveil might want bun *, citadel might want go test *). Could support an optional per-repo template at {repo_root}/.claude/crow-session-allow.json that we additionally merge. Not blocking — punt to a follow-up.
  • Skill files vs. dev-root: prefer dropping the template in the skill directory (.claude/skills/crow-workspace/) over hardcoding in the script, so editing the allowlist doesn't require editing bash.

Acceptance criteria

  • setup.sh writes a baseline .claude/settings.local.json into each new worktree before launching Claude Code.
  • The baseline covers every command the crow prompt template instructs the session to run on step 1 (especially gh issue view, glab issue view, gh pr view).
  • Existing .claude/settings.local.json files in a worktree are not overwritten.
  • A worktree session opened with /crow-workspace runs the entire "study the ticket → propose plan" flow without permission prompts on the listed commands.
  • The template is in a single place (skill dir) and easy to edit.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions