chore(config): centralize git for teammates and enable tmux panes
Two agent-team tooling changes: - teammateMode: in-process -> auto. Teammates now spawn in tmux split panes when the lead runs inside tmux, with graceful in-process fallback. - New PreToolUse hook git-centralize-guard.sh blocks .git-mutating commands (add, commit, merge, push, pull, rebase, reset, checkout, stash, cherry-pick, rm, mv) for teammates, keeping version control centralized to the lead. Detection keys on the agent_type field, which a teammate's hook input carries and the lead's does not. Read-only git is allowed. Documented in .claude/rules/git-safety.md. Hooks load at lead startup, so a restart is required for the hook to reach teammates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
# git-centralize-guard: PreToolUse hook that blocks .git-mutating commands for
|
||||
# agent-team teammates. Version control is centralized to the team lead
|
||||
# (see CLAUDE.md / memory: "Team lead commits, never agents").
|
||||
#
|
||||
# Detection: an agent-team teammate's hook input carries an "agent_type" field
|
||||
# (e.g. "qatux"); the team lead's main session does NOT. So agent_type present
|
||||
# => a teammate (or subagent) => block git writes. Absent => the lead => allow.
|
||||
# (Empirically confirmed on Claude Code 2.1.148; docs field is "agent_type".)
|
||||
#
|
||||
# Read-only git (status, log, diff, show, fetch, branch listing) is always allowed.
|
||||
set -uo pipefail
|
||||
|
||||
INPUT=$(cat)
|
||||
|
||||
# Only act on Bash tool calls
|
||||
TOOL_NAME=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_name',''))" 2>/dev/null)
|
||||
[ "$TOOL_NAME" = "Bash" ] || exit 0
|
||||
|
||||
# Teammates/subagents carry agent_type; the lead does not.
|
||||
AGENT_TYPE=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('agent_type','') or '')" 2>/dev/null)
|
||||
[ -n "$AGENT_TYPE" ] || exit 0 # lead -> allow everything
|
||||
|
||||
COMMAND=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_input',{}).get('command',''))" 2>/dev/null)
|
||||
|
||||
# Block git history/working-tree-mutating subcommands anywhere in the command
|
||||
# (catches chained forms like `cd x && git commit`). Read-only git is allowed.
|
||||
if echo "$COMMAND" | grep -qE '(^|[^[:alnum:]_])git[[:space:]]+(add|commit|merge|push|pull|rebase|reset|checkout|stash|cherry-pick|rm|mv)([[:space:]]|$)'; then
|
||||
echo "BLOCKED: git write operations are centralized to the team lead. Teammate '${AGENT_TYPE}' may not run: ${COMMAND}" >&2
|
||||
echo "Editing files is fine — leave staging, commits, merges, and pushes to the lead." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -7,6 +7,21 @@
|
||||
- Skip files in `.gitignore`
|
||||
- The `.claude/` directory IS tracked — skills and agents belong in the repo
|
||||
|
||||
## Centralized version control (agent teams)
|
||||
|
||||
Git is the **team lead's** job. Teammates edit files; the lead stages, commits,
|
||||
merges, and pushes. This is enforced, not just convention:
|
||||
|
||||
- **Hook:** `.claude/hooks/git-centralize-guard.sh` (PreToolUse on Bash) blocks
|
||||
`.git`-mutating commands — `add`, `commit`, `merge`, `push`, `pull`, `rebase`,
|
||||
`reset`, `checkout`, `stash`, `cherry-pick`, `rm`, `mv` — for any agent-team
|
||||
teammate. Read-only git (`status`, `log`, `diff`, `show`, `fetch`) is allowed.
|
||||
- **Detection:** a teammate's PreToolUse hook input carries an `agent_type` field
|
||||
(e.g. `"qatux"`); the lead's main session does not. Present → block; absent →
|
||||
allow. (Confirmed on Claude Code 2.1.148.)
|
||||
- **Activation:** hooks load at lead startup and teammates inherit that snapshot,
|
||||
so changes to this hook require a Claude Code restart to reach teammates.
|
||||
|
||||
## Commit conventions
|
||||
|
||||
Use conventional commits: `<type>(<scope>): <summary>`
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1",
|
||||
"SR_DB_PATH": "/var/home/jeroenschweitzer/Projects/settled-reach/settledreach.db"
|
||||
},
|
||||
"teammateMode": "in-process",
|
||||
"teammateMode": "auto",
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(git add *)",
|
||||
@@ -87,6 +87,11 @@
|
||||
"type": "command",
|
||||
"command": ".claude/hooks/git-lock-guard.sh",
|
||||
"timeout": 5
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"command": ".claude/hooks/git-centralize-guard.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user