Hawkeye — Workflow
Session Lifecycle
hawkeye init
→ Create .hawkeye/ directory
→ Write .hawkeye/config.json (default config)
→ Create .hawkeye/traces.db (SQLite)
hawkeye hooks install
→ Write Claude Code hooks to settings.json
→ PreToolUse: hawkeye hook-handler --event PreToolUse
→ PostToolUse: hawkeye hook-handler --event PostToolUse
→ Stop: hawkeye hook-handler --event Stop
Claude Code Hook Flow (Primary Path)
Claude Code fires PreToolUse
→ hook-handler reads JSON from stdin
→ Evaluate guardrails:
checkFileProtection(toolName, toolInput, config)
checkDangerousCommand(toolName, toolInput, config)
checkDirectoryScope(toolName, toolInput, config)
checkNetworkLock(toolName, toolInput, config)
checkReviewGate(toolName, toolInput, config)
→ Violation found → write JSON to stdout (exit 2 = block)
→ No violation → allow (exit 0)
→ Record PreToolUse event in traces.db
Claude Code fires PostToolUse
→ hook-handler reads JSON from stdin
→ Record completed action with full data:
- toolName, toolInput, toolOutput
- Bash output capture
- File content snapshots (before/after for diffs)
- LLM cost estimation via JSONL reader
- Git branch/commit context
→ Compute incremental drift score (heuristic or LLM)
→ Save TraceEvent to traces.db
Claude Code fires Stop
→ NOTE: Stop fires after EVERY response, not just session end
→ Do NOT close session — update drift snapshot only
→ Persist current drift score to traces.db
→ Session ends manually via "hawkeye end" or dashboard timeout
Record Mode (Non-Claude Agents)
hawkeye record -o "objective" -- <command>
→ Spawn child process
→ Inject Node.js preload script (--require hook)
→ Patch global fetch + http/https.request
→ Intercept LLM API calls (Anthropic, OpenAI, Deepseek, Mistral, Google)
- Detect provider from URL
- Parse SSE streaming and JSON responses
- Extract input/output tokens → estimate cost
→ Forward to NetworkLock check → block or allow
→ Record llm_call events to traces.db
→ On process exit → finalize session
LLM Cost Reading (Claude Code Specific)
PostToolUse hook
→ Read ~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl
→ Parse JSONL from last-read offset (incremental)
→ Extract usage.input_tokens, usage.output_tokens, model
→ Deduplicate by message ID (streaming sends same ID multiple times)
→ Compute cost via cost table (sonnet/opus/haiku per 1M tokens)
→ Attach to TraceEvent
Drift Detection
Per PostToolUse:
scoreHeuristic(session, recentEvents, objective)
→ Keyword overlap, action relevance, error frequency
→ Returns 0-100 score
slidingDriftScore(history)
→ Weighted average over recent N events
→ More recent events weighted higher
Optional LLM drift:
→ Call configured provider with objective + recent events
→ LLM rates alignment 0-100
→ Cached, not run on every event
Thresholds:
ok: 70-100
warning: 40-69
critical: 0-39
Guardrail Block Flow
PreToolUse violation detected:
→ Write guardrail block response to stdout:
{ "decision": "block", "reason": "<message>" }
→ Exit 2 (Claude Code interprets as block)
→ Record guardrail_block event in traces.db
Review gate (require_approval):
→ Write file-based approval request
→ Poll for human approval before proceeding
→ On timeout → deny
Overnight Mode
hawkeye overnight --budget <$N>
→ Apply cost limits, file protection, command blocking
→ Start hawkeye serve (web dashboard)
→ Start hawkeye daemon (background recorder)
→ Auto-pause on critical drift
→ Backup .hawkeye/config.json
→ On Ctrl+C:
→ Generate morning report (per-session stats, drift, errors)
→ Optionally: LLM post-mortem
→ Fire webhooks: overnight_report, session_complete, task_complete
→ Restore original config
Phase-to-Artifact Map
| Phase |
Artifact |
| hawkeye init |
.hawkeye/config.json, .hawkeye/traces.db |
| PreToolUse |
TraceEvent (guardrail_block or pre-action record) |
| PostToolUse |
TraceEvent (command/file_write/llm_call/etc.) with cost+drift |
| Stop |
Drift snapshot update in traces.db |
| hawkeye end |
Session row marked completed, final drift saved |
| hawkeye report |
Markdown/text report from session data |
| post_mortem MCP tool |
LLM-generated structured post-mortem |