.claude/ — Claude Code Configuration
This directory configures Claude Code for the AIPass project.
Related: DPLAN-0053 (Hook Migration) documents the research and decisions behind this architecture.
Quick Setup
AIPass hooks live in two places. The project hooks (hooks/) travel with the repo. The global hooks (global_hooks/) need to be copied to your ~/.claude/ directory.
Step 1: Copy global hooks
# Copy hook scripts to your Anthropic hooks directory
mkdir -p ~/.claude/hooks
cp .claude/global_hooks/*.py ~/.claude/hooks/
cp .claude/global_hooks/*.sh ~/.claude/
# Optional: copy sounds (if you want audio feedback)
mkdir -p ~/.claude/sounds
cp .claude/sounds/* ~/.claude/sounds/ 2>/dev/null || true
Step 2: Configure global settings
Add these entries to your ~/.claude/settings.json. These use git rev-parse to find the repo — no hardcoded paths needed.
UserPromptSubmit hooks (inject prompts every turn):
"UserPromptSubmit": [
{
"hooks": [{ "type": "command", "command": "REPO=$(git rev-parse --show-toplevel 2>/dev/null) && [ -f \"$REPO/.aipass/aipass_global_prompt.md\" ] && cat \"$REPO/.aipass/aipass_global_prompt.md\" || true" }]
},
{
"hooks": [{ "type": "command", "command": "REPO=$(git rev-parse --show-toplevel 2>/dev/null) && [ -f \"$REPO/.claude/hooks/branch_prompt_loader.py\" ] && python3 \"$REPO/.claude/hooks/branch_prompt_loader.py\" || true" }]
},
{
"hooks": [{ "type": "command", "command": "REPO=$(git rev-parse --show-toplevel 2>/dev/null) && [ -f \"$REPO/.claude/hooks/identity_injector.py\" ] && python3 \"$REPO/.claude/hooks/identity_injector.py\" || true" }]
},
{
"hooks": [{ "type": "command", "command": "REPO=$(git rev-parse --show-toplevel 2>/dev/null) && [ -f \"$REPO/.claude/hooks/email_notification.py\" ] && python3 \"$REPO/.claude/hooks/email_notification.py\" || true" }]
},
{
"hooks": [{ "type": "command", "command": "echo \"# Current Time: $(date +'%A, %B %-d %Y — %-I:%M %p')\"" }]
}
]
PreCompact hooks (save context before compaction):
"PreCompact": [
{ "matcher": "manual", "hooks": [{ "type": "command", "command": "REPO=$(git rev-parse --show-toplevel 2>/dev/null) && [ -f \"$REPO/.claude/hooks/pre_compact.py\" ] && python3 \"$REPO/.claude/hooks/pre_compact.py\" || true", "timeout": 60 }] },
{ "matcher": "auto", "hooks": [{ "type": "command", "command": "REPO=$(git rev-parse --show-toplevel 2>/dev/null) && [ -f \"$REPO/.claude/hooks/pre_compact.py\" ] && python3 \"$REPO/.claude/hooks/pre_compact.py\" || true", "timeout": 60 }] }
]
Optional hooks (sounds, auto-fix — from global_hooks/):
"PreToolUse": [
{ "matcher": "Bash|Edit|MultiEdit|Write|Read|Grep|Glob|WebSearch|WebFetch|Task",
"hooks": [{ "type": "command", "command": "python3 ~/.claude/hooks/tool_use_sound.py" }] }
],
"PostToolUse": [
{ "matcher": "Edit|MultiEdit|Write|NotebookEdit",
"hooks": [{ "type": "command", "command": "python3 ~/.claude/hooks/auto_fix_diagnostics.py" }] }
],
"Stop": [
{ "hooks": [{ "type": "command", "command": "python3 ~/.claude/hooks/stop_sound.py" }] }
],
"Notification": [
{ "hooks": [{ "type": "command", "command": "python3 ~/.claude/hooks/notification_sound.py" }] }
]
Step 3: Done
Launch Claude from any branch subdirectory:
cd src/aipass/devpulse
claude --permission-mode bypassPermissions
The hooks will auto-discover the repo root and inject the right prompts.
Why This Architecture
Claude Code project settings (.claude/settings.json) don't fire UserPromptSubmit hooks from subdirectories — only from the repo root. Since AIPass citizens launch from src/aipass/{name}/, we can't use project settings for prompt injection.
The solution: hooks live in global settings (~/.claude/settings.json) but use git rev-parse --show-toplevel to find the repo dynamically. No hardcoded paths. Works for any clone location, any user. Outside a git repo, hooks silently do nothing.
See DPLAN-0053 for the full investigation and test results.
What's In This Directory
.claude/
├── settings.json # Project settings (permissions, env vars, PostToolUse, SubagentStop)
├── hooks/ # AIPass-specific hook scripts (travel with repo)
│ ├── branch_prompt_loader.py # Injects branch-specific prompt based on CWD
│ ├── identity_injector.py # Injects passport identity (role, traits, purpose)
│ ├── email_notification.py # Notifies if unread mail exists
│ ├── pre_compact.py # Saves session context before compaction
│ ├── prompt_inject.sh # Combined inject (reference, not used in production)
│ └── .archive/ # Archived/disabled hooks
├── global_hooks/ # Scripts to copy to ~/.claude/hooks/ (user setup)
│ ├── auto_fix_diagnostics.py # Syntax check + seedgo checklist after edits
│ ├── subagent_stop_gate.py # Blocks subagent if modified files have violations
│ ├── tool_use_sound.py # Keypress sound on tool calls
│ ├── stop_sound.py # Sound on stop
│ ├── notification_sound.py # Sound on notification
│ ├── hook_logger.sh # Optional hook activity logger
│ └── statusline.sh # Statusline display (branch, model, context, cost)
├── agents/ # Agent definitions
│ └── builder.md
├── commands/ # Slash commands
│ └── memo.md # /memo — memory update workflow
├── sounds/ # Audio files for sound hooks
└── README.md # This file
What Gets Injected Every Turn
- Global Prompt — system context, terminology, commands, rules (
.aipass/aipass_global_prompt.md) - Branch Prompt — branch-specific instructions based on CWD (
.aipass/aipass_local_prompt.md) - Identity — passport summary: role, traits, purpose (
.trinity/passport.json) - Email — notification only if unread mail exists (
.ai_mail.local/inbox.json) - Time Clock — current date and time for temporal awareness (added S72, inline shell command)
Project Settings
Defined in settings.json (this directory). These DO fire from subdirectories.
Environment:
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1— makes PostToolUse hooks fire inside subagents
Permissions:
- Denied:
git reset,git rebase,git config,git push --force,EnterPlanMode - Default mode:
acceptEdits
Project hooks:
PostToolUse— auto-fix diagnostics after file edits (fires in subagents via env var)SubagentStop— secondary gate checking modified files against seedgo standards
Time Clock Hook (S72)
What: Injects # Current Time: Thursday, April 2 2026 — 11:24 AM as its own system-reminder every turn.
Why: Claude has no temporal awareness by default — doesn't know what time it is, how long a session has been running, or whether it's day/night. The user requested this in S71 as the first step toward autonomous scheduling, task duration estimation, and personal reminders. A year-old wishlist item finally built.
How: Pure inline shell — no script file. Added as a separate entry in ~/.claude/settings.json UserPromptSubmit array so it gets its own system-reminder block (not buried in the 13.6KB global prompt output).
Important: This hook lives ONLY in ~/.claude/settings.json (global). It's not a repo script — it's a one-liner echo with date. First attempt put it inside prompt_inject.sh but it got truncated by the 2KB preview limit since the global prompt is 13.6KB. Moving it to its own hook entry fixed visibility.
Future: This is proof-of-concept for a broader temporal awareness system — session duration tracking, task time estimation, reminders (bedtime, meals), autonomous work scheduling.
Adding a New Hook
- Create the script in
.claude/hooks/ - Add one entry to
~/.claude/settings.jsonusing thegit rev-parsepattern:REPO=$(git rev-parse --show-toplevel 2>/dev/null) && [ -f "$REPO/.claude/hooks/your_script.py" ] && python3 "$REPO/.claude/hooks/your_script.py" || true - Done — no hardcoded paths, works for any clone location