Skip to main content

Claude Code Hooks Setup

Status: ⚠️ Partially Working (October 25, 2025)

The AILANG repository is configured with Claude Code hooks for agent integration. Hooks execute successfully but output doesn't reliably appear in Claude's context. Manual workflow is recommended.

What's Configured

Hooks Enabled

  1. Stop Hook (scripts/hooks/agent_handoff.sh)

    • Triggers: When you stop a Claude Code session
    • Action: Detects design docs in design_docs/planned/ modified in last 5 minutes
    • Sends to: sprint-planner agent with content-addressed artifacts
  2. SessionStart Hook (scripts/hooks/session_start.sh)

    • Triggers: When you start a Claude Code session
    • Actions:
      • Checks both inbox locations (user + claude-code)
      • Outputs message summaries to stdout
      • Does NOT auto-mark as read (prevents race conditions)
    • ⚠️ Known Issue: Output doesn't reliably appear in Claude's context
    • Workaround: Ask Claude to run ailang agent inbox --unread-only claude-code

Configuration File

.claude/settings.local.json - Hooks configured here (NOT hooks.json!)

.claude/settings.local.json
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "command",
"command": "bash \"$CLAUDE_PROJECT_DIR\"/scripts/hooks/agent_handoff.sh",
"timeout": 30
}]
}],
"SessionStart": [{
"hooks": [{
"type": "command",
"command": "bash \"$CLAUDE_PROJECT_DIR\"/scripts/hooks/session_start.sh",
"timeout": 10
}]
}]
}
}

Note: Hooks must use $CLAUDE_PROJECT_DIR for absolute paths.

Quick Test

Test 1: Send a Message to Yourself

ailang agent send --to-user '{"message": "Testing hooks", "status": "ready"}'

Test 2: Check Your Inbox

# Check user inbox
ailang agent inbox --unread-only user

# Check claude-code inbox (project-specific)
ailang agent inbox --unread-only claude-code

⚠️ Note: Flags must come BEFORE agent ID!

Expected output:

📬 user Inbox (1 message)
================================================================================

▶ Message 1/1
ID: msg_...
From: cli-sender
Type: request
Payload: {"message":"Testing hooks","status":"ready"}

Test 3: Trigger SessionStart Hook

bash scripts/hooks/session_start.sh

Expected output:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📬 AGENT INBOX: 1 unread message(s) from autonomous agents
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

From: cli-sender
Time: 2025-10-25T12:00:00Z
Message: {"message":"Testing hooks","status":"ready"}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
💡 Review the messages above and decide if any action is needed.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

To verify hook executed:

tail -10 ~/.ailang/state/hooks.log
# Should show: "Found 1 unread message(s) across all inbox locations"

⚠️ Known Issue: This output doesn't reliably appear in Claude Code's context. Use the manual workflow instead.

Since automatic context injection doesn't reliably work, use this manual workflow:

When Starting a New Session

  1. You ask Claude: "Check inbox" or "Any agent messages?"

  2. Claude runs:

    ailang agent inbox --unread-only claude-code
  3. Claude sees messages and tells you about them

  4. Claude processes tasks (reviews sprint, implements features, etc.)

  5. Claude acknowledges when done:

    # If all tasks completed successfully:
    ailang agent ack --all

    # If specific task completed:
    ailang agent ack msg_20251025_155729_a5f3e77ee975

    # If task failed (to retry in next session):
    ailang agent unack msg_20251025_155729_a5f3e77ee975

How It Works

Two Inbox Locations

User Inbox (~/.ailang/state/messages/inbox/user/):

  • Home directory, persists across projects
  • For messages TO the user from any agent
  • Check with: ailang agent inbox --unread-only user

Claude-Code Inbox (.ailang/state/messages/claude-code/):

  • Project directory, specific to this codebase
  • For messages TO claude-code agent
  • Check with: ailang agent inbox --unread-only claude-code
  • SessionStart hook queries this location

SessionStart Hook Behavior

When you start a Claude Code session, the SessionStart hook:

  1. Checks both inboxes for unread messages
  2. Outputs summary to stdout (formatted, human-readable)
  3. Does NOT auto-mark as read (prevents race conditions)
  4. Logs activity to ~/.ailang/state/hooks.log

⚠️ Known Limitation: Hook output doesn't reliably appear in Claude's context (Claude Code limitation).

Message Lifecycle

1. Agent sends message

2. Lands in _unread or .pending.json

3. Claude checks inbox (user asks)

4. Claude processes task

5a. SUCCESS → ailang agent ack

Moves to _processed or _read

5b. FAILURE → ailang agent unack

Moves back to _unread

Next session sees it again

Agent Handoff Workflow Example

Step by step:

  1. You: "Analyze eval failures and create a design doc"
  2. Claude Code: Creates design_docs/planned/M-FIX-123.md
  3. You: "Looks good" (session stops)
  4. Stop Hook:
    • Detects the new design doc
    • Computes SHA256 hash: ailang debug hash design_docs/planned/M-FIX-123.md
    • Sends to sprint-planner: ailang agent send sprint-planner {...}
  5. Autonomous Agents: Implement, test, report back to user inbox
  6. Next Session: SessionStart hook shows notification
  7. You: ailang agent inbox user - See completion message!

State Directory

Location: ~/.ailang/state/ (home directory)

Structure:

~/.ailang/state/
├── messages/
│ ├── inbox/
│ │ └── user/
│ │ ├── _unread/ # New notifications
│ │ ├── _read/ # Viewed messages
│ │ └── _archive/ # Old messages
│ ├── sprint-planner/ # Agent inbox
│ └── sprint-executor/ # Agent inbox
├── artifacts/
│ └── sha256/ # Content-addressed storage
└── hooks.log # Hook execution log

Monitoring

View Hook Logs

tail -f ~/.ailang/state/hooks.log

Check Agent Status

ailang agent top

View Dead Letter Queue

ailang agent dlq --list

Troubleshooting

Hooks not firing?

  1. Check hook logs:

    tail -f ~/.ailang/state/hooks.log
  2. Test manually:

    export CLAUDE_HOOK_JSON='{"sessionId": "test", "userId": "user", "event": "Stop"}'
    bash scripts/hooks/agent_handoff.sh
  3. Verify permissions:

    ls -la scripts/hooks/*.sh
    # Should show: -rwxr-xr-x (executable)

Messages not appearing?

  1. Check inbox location:

    ls -la ~/.ailang/state/messages/inbox/user/_unread/
  2. Send test message:

    ailang agent send --to-user '{"test": "message"}'
    ailang agent inbox user
  3. Check state directory:

    echo $STATE_DIR  # Should be empty (uses default)
    # Default: ~/.ailang/state

Design documents (GitHub):

Success Metrics

From production testing (October 25, 2025):

MetricTargetStatus
Handoff latency<5s✅ ~3-4s measured
Message delivery100%✅ Soak tested
Hook reliabilityNo failures✅ Tested working
DocumentationComplete✅ Docusaurus ready

Status: ✅ All hooks configured and tested. Ready for production use!

Next Steps:

  1. Create a design doc in Claude Code
  2. Stop the session
  3. Check ailang agent inbox sprint-planner for the handoff message
  4. Start a new session - see the notification!

Questions?