Skip to content

Hook Engine - Per-Turn State Injection for Claude Code

CCG installs 4 hooks into ~/.claude/settings.json. Each hook is pure JavaScript with zero dependencies. If a hook fails, it exits silently without disrupting your workflow.

HookEventPurpose
workflow-state.jsUserPromptSubmitInjects task state breadcrumb every turn
session-start.jsSessionStartInjects full project context on session start/compaction
subagent-context.jsPreToolUseInjects spec + task context into sub-agents
skill-router.jsUserPromptSubmitAuto-injects domain knowledge on keyword detection

Event: UserPromptSubmit (fires every time the user sends a message)

Purpose: Reads the active task’s task.json and injects the current task state as a prefix to the user’s message.

Injection format:

<ccg-state>
Task: add-jwt-auth (in_progress)
Strategy: full-collaborate
Phase: 4-implementation
Next: Layer 1 Builders executing
</ccg-state>

How it works:

  1. Scans .ccg/tasks/ for tasks with in_progress status
  2. Reads strategy, phase, and gate fields from task.json
  3. Generates a <ccg-state> XML block
  4. Prepends it to the user’s message (invisible to the user, visible to Claude)

Event: SessionStart (fires on session start, context clear, and context compaction)

Purpose: Injects full project context and active task state, ensuring Claude does not lose critical information after compaction.

Injected content:

  • Project tech stack information
  • Full state of the active task (including plan and progress)
  • References to relevant spec files
  • Outstanding HARD STOP checkpoints

Why this is necessary:

Claude Code has a finite context window. When conversations grow long, early context gets compacted or dropped. session-start.js re-injects essential state after compaction, achieving zero state loss.

Event: PreToolUse (fires before Bash or Agent tool calls)

Purpose: When it detects a codeagent-wrapper invocation or an Agent Teams TeamCreate operation, it automatically injects project specs and task context.

Trigger conditions:

  • Calling codeagent-wrapper --backend codex/gemini
  • Spawning a Builder teammate via TeamCreate

Injected content:

  • Reads context.jsonl from the task directory to get the relevant spec file list
  • Loads corresponding spec files from .ccg/spec/ and injects their content into the sub-agent’s prompt
  • Injects the current task plan and constraints

Result: Sub-agents — whether external models (Codex/Gemini) or Team Builders — automatically follow your project’s coding standards without manual copy-pasting.

Main Claude calls codeagent-wrapper
subagent-context.js intercepts
Reads .ccg/tasks/current/context.jsonl
Injects spec/backend/index.md content into prompt
codeagent-wrapper executes (with spec context)

Event: UserPromptSubmit (fires every time the user sends a message)

Purpose: Scans the user’s message for domain keywords and auto-injects the corresponding knowledge file into context.

Keyword mapping examples:

Detected KeywordsInjected Knowledge File
penetration, red team, exploitdomains/security/red-team.md
caching, Redis, CDNdomains/architecture/caching.md
RAG, vector databasedomains/ai/rag-system.md
performance, profilingdomains/devops/performance.md

How it works:

  1. Performs keyword matching on the user’s message (supports both Chinese and English)
  2. On match, reads the corresponding knowledge file from ~/.claude/skills/ccg/domains/
  3. Injects the file content into context
  4. Each knowledge file is injected only once per session (avoids duplication)

All hooks are registered in ~/.claude/settings.json:

{
"hooks": {
"UserPromptSubmit": [
{
"type": "command",
"command": "node ~/.claude/hooks/ccg/workflow-state.js"
},
{
"type": "command",
"command": "node ~/.claude/hooks/ccg/skill-router.js"
}
],
"SessionStart": [
{
"type": "command",
"command": "node ~/.claude/hooks/ccg/session-start.js"
}
],
"PreToolUse": [
{
"type": "command",
"command": "node ~/.claude/hooks/ccg/subagent-context.js"
}
]
}
}
  • Zero dependencies — Pure Node.js standard library, no packages to install
  • Silent failure — Hooks exit(0) on error, never blocking your workflow
  • Idempotent — Multiple executions produce consistent results with no duplicate injection
  • Lightweight — Each hook executes in under 50ms