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>
35 lines
1.8 KiB
Bash
Executable File
35 lines
1.8 KiB
Bash
Executable File
#!/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
|