Continuous-Claude-v2 vs fasthooks¶
Continuous-Claude-v2 is a session continuity system that preserves context across Claude Code sessions. This page compares its hook implementation with fasthooks.
Different Goals¶
| Aspect | Continuous-Claude-v2 | fasthooks |
|---|---|---|
| Primary Purpose | Session continuity | Hook development framework |
| Philosophy | Preserve state across clears | Build custom hook logic |
| Core Feature | Ledgers + handoffs | Typed events + DI |
| Target User | Power users wanting continuity | Developers building hooks |
Continuous-Claude-v2 solves context degradation - when Claude compacts, you lose signal. Instead of fighting compaction, it embraces /clear with preserved state via ledgers and handoffs.
fasthooks is a framework for building any hook logic - security policies, rate limiting, code review, integrations.
Architecture Comparison¶
Continuous-Claude-v2: Pre-bundled TypeScript¶
.claude/hooks/
├── src/ # TypeScript source
│ ├── session-start-continuity.ts
│ ├── typescript-preflight.ts
│ └── ...
├── dist/ # Pre-compiled JS (committed)
│ ├── session-start-continuity.mjs
│ └── ...
├── *.sh # Shell wrappers
│ ├── session-start.sh → node dist/session-start-continuity.mjs
│ └── ...
└── build.sh # Rebuild after source changes
Deployment: Copy .claude/hooks/, make scripts executable. No npm install needed.
fasthooks: Pure Python¶
# hooks.py
from fasthooks import HookApp, deny
app = HookApp()
@app.pre_tool("Bash")
def check_bash(event):
if "rm -rf" in event.command:
return deny("Blocked")
if __name__ == "__main__":
app.run()
Deployment: pip install fasthooks, point Claude Code to python hooks.py.
Hook Events Supported¶
| Event | Continuous-Claude | fasthooks |
|---|---|---|
| SessionStart | ✅ | ✅ |
| PreToolUse | ✅ | ✅ |
| PostToolUse | ✅ | ✅ |
| PreCompact | ✅ | ✅ |
| UserPromptSubmit | ✅ | ✅ |
| SubagentStop | ✅ | ✅ |
| SessionEnd | ✅ | ✅ |
| Stop | ❌ | ✅ |
| Notification | ❌ | ✅ |
| PermissionRequest | ❌ | ✅ |
Both cover core events. fasthooks has broader coverage.
Response Format¶
Continuous-Claude-v2: Manual JSON¶
// Block decision (PreToolUse only)
console.log(JSON.stringify({
decision: 'block',
reason: 'TypeScript errors found:\n Line 15: Property does not exist'
}));
// Context injection
console.log(JSON.stringify({
result: 'continue',
hookSpecificOutput: {
hookEventName: 'SessionStart',
additionalContext: ledgerContent + '\n\n' + handoffContent
}
}));
// Simple continue
console.log(JSON.stringify({ continue: true }));
fasthooks: Helper Functions¶
from fasthooks import allow, deny, block
@app.pre_tool("Bash")
def check(event):
if dangerous(event.command):
return deny("Blocked") # Block with reason
return allow(message="Approved") # Continue with message
@app.on_stop()
def prevent_stop(event):
return block("Keep working") # Prevent stopping
| Aspect | Continuous-Claude | fasthooks |
|---|---|---|
| Block tool | decision: 'block' |
deny("reason") |
| Allow | continue: true |
allow() or None |
| Inject context | hookSpecificOutput.additionalContext |
allow(message=...) |
| Block stop | Not supported | block("reason") |
Blocking Capability¶
Continuous-Claude-v2: PreToolUse Only¶
// typescript-preflight.ts - blocks on type errors
if (checkResult.has_errors) {
console.log(JSON.stringify({
decision: 'block',
reason: `⚠️ TypeScript Pre-flight: ${checkResult.summary}`
}));
return;
}
Only PreToolUse can block. Other events just continue or inject context.
fasthooks: Any Event¶
@app.pre_tool("Write")
def check_write(event):
if ".env" in event.file_path:
return deny("Cannot modify .env")
@app.on_stop()
def require_tests(event, transcript: Transcript):
if transcript.stats.tool_calls.get("Bash", 0) == 0:
return block("Run tests before stopping")
@app.on_prompt()
def rate_limit(event, state: State):
if state.get("prompts", 0) > 100:
return deny("Rate limit exceeded")
Any handler can deny/block, not just PreToolUse.
State Management¶
Continuous-Claude-v2: Three-Layer System¶
Layer 1: Continuity Ledger (within-session)
<!-- thoughts/ledgers/CONTINUITY_CLAUDE-myproject.md -->
## Goal
Implement payment integration
## State
- Done: Auth system ✓
- Now: Payment webhooks
- Next: Stripe sandbox tests
Layer 2: Handoffs (between-session)
<!-- thoughts/shared/handoffs/session-123/task-1.md -->
---
root_span_id: abc-123
outcome: PARTIAL_PLUS
---
## Context
Working on payment webhooks...
## Key Decisions
- Using Stripe webhooks over polling
Layer 3: Artifact Index (searchable history)
-- .claude/cache/artifact-index/context.db (SQLite + FTS5)
SELECT * FROM handoffs
WHERE outcome = 'FAILED'
AND what_failed LIKE '%authentication%'
fasthooks: Dependency Injection¶
from fasthooks.depends import State, Transcript
@app.pre_tool("Bash")
def handler(event, state: State, transcript: Transcript):
# state: JSON file per session, auto-loaded
state["command_count"] = state.get("command_count", 0) + 1
state.save()
# transcript: Parsed history with stats
print(f"Total tokens: {transcript.stats.total_tokens}")
| Aspect | Continuous-Claude | fasthooks |
|---|---|---|
| State format | Markdown ledgers | JSON dict |
| Persistence | File-based (3 layers) | File-based (1 layer) |
| Searchable | SQLite + FTS5 | No built-in search |
| Complexity | High (rich context) | Low (simple state) |
| Setup | Requires directory structure | Zero setup |
Unique Features¶
Continuous-Claude-v2¶
1. TypeScript Preflight
// PreToolUse runs tsc --noEmit before Edit/Write on .ts files
if (checkResult.has_errors) {
return { decision: 'block', reason: errorSummary };
}
2. Skill Auto-Activation
// skill-rules.json
{
"skills": {
"morph-search": {
"priority": "high",
"promptTriggers": {
"keywords": ["search", "grep", "find"]
}
}
}
}
3. Auto-Handoff on Compact
PreCompact hook automatically: 1. Parses transcript 2. Generates handoff with file:line references 3. SessionStart loads it on resume
No manual handoff needed.
4. Outcome Tracking
Mark handoff outcomes, query past failures to improve decisions.5. Context Percentage Warnings
Reads /tmp/claude-context-pct-{SESSION}.txt, shows warnings:
- <60%: Normal
- 60-79%: Yellow warning
- 80%+: Red critical
6. Pre-bundled Deployment
No npm install - just copy .claude/hooks/ and run.
fasthooks¶
1. Response Helpers
deny("reason") # Block with message
block("reason") # Prevent stop
allow(message="...") # Continue with feedback
2. Dependency Injection
def handler(event, state: State, transcript: Transcript, tasks: Tasks):
# All dependencies auto-injected
3. Blueprints
4. Guards
@app.pre_tool("Bash", when=lambda e: "sudo" in e.command)
def check_sudo(event):
return deny("No sudo")
5. Background Tasks
@task
def analyze(code: str) -> str:
return expensive_analysis(code)
@app.pre_tool("Write")
def on_write(event, tasks: Tasks):
tasks.add(analyze, event.content)
6. Testing Utilities
client = TestClient(app)
response = client.send(MockEvent.bash(command="rm -rf /"))
assert response.decision == "deny"
Developer Experience¶
Continuous-Claude-v2: TypeScript + Shell¶
// .claude/hooks/src/my-hook.ts
import { readFileSync } from 'fs';
interface Input {
session_id: string;
cwd: string;
tool_name: string;
tool_input: any;
}
const input: Input = JSON.parse(readFileSync('/dev/stdin', 'utf-8'));
if (input.tool_name === 'Bash' && input.tool_input.command.includes('rm')) {
console.log(JSON.stringify({ decision: 'block', reason: 'Blocked' }));
} else {
console.log(JSON.stringify({ continue: true }));
}
Workflow:
1. Edit TypeScript in src/
2. Run ./build.sh to compile
3. Test by running hook manually
4. Commit dist/ for deployment
fasthooks: Pure Python¶
# hooks.py
from fasthooks import HookApp, deny
app = HookApp()
@app.pre_tool("Bash")
def check_bash(event):
if "rm" in event.command:
return deny("Blocked")
if __name__ == "__main__":
app.run()
Workflow:
1. Write Python
2. Run tests with TestClient
3. Deploy
Feature Matrix¶
| Feature | Continuous-Claude | fasthooks |
|---|---|---|
| Hook Framework | Partial (specialized) | ✅ (general purpose) |
| Deny/Block | PreToolUse only | Any event |
| Typed Events | TypeScript interfaces | Pydantic models |
| Property Accessors | Manual (input.tool_input.x) |
event.command |
| State Persistence | ✅ (3-layer) | ✅ (simple) |
| Transcript Parsing | ✅ (for handoffs) | ✅ (built-in) |
| Background Tasks | ❌ | ✅ |
| Blueprints | ❌ | ✅ |
| Middleware | ❌ | ✅ |
| Guards | ❌ | ✅ |
| Testing Utils | ❌ | ✅ |
| Skills System | ✅ | ❌ |
| TypeScript Preflight | ✅ | ❌ |
| Auto-Handoff | ✅ | ❌ |
| Outcome Tracking | ✅ | ❌ |
| Zero-Config Deploy | ✅ (pre-bundled) | Requires pip |
When to Use Each¶
Use Continuous-Claude-v2 When:¶
- You want session continuity across
/clearand compaction - You need ledgers and handoffs for complex multi-session work
- You want TypeScript type checking before edits
- You need skill auto-activation based on keywords
- You want outcome tracking to learn from past sessions
- You prefer pre-bundled deployment (no pip/npm at runtime)
Use fasthooks When:¶
- You're building custom hooks with any logic
- You need to block on any event (not just PreToolUse)
- You want typed events with IDE autocomplete
- You need dependency injection (State, Transcript, Tasks)
- You want modular composition (blueprints, middleware)
- You need easy testing with mock events
- You want background tasks for async work
Using Both Together¶
The systems serve different purposes and can coexist:
{
"hooks": {
"SessionStart": [
{ "command": "~/.claude/hooks/session-start.sh" }
],
"PreToolUse": [
{ "command": "python /path/to/fasthooks/security.py" },
{ "command": "~/.claude/hooks/typescript-preflight.sh" }
],
"PostToolUse": [
{ "command": "~/.claude/hooks/handoff-index.sh" }
],
"PreCompact": [
{ "command": "~/.claude/hooks/pre-compact.sh" }
]
}
}
- Continuous-Claude for session continuity (ledgers, handoffs, context injection)
- fasthooks for policy enforcement (security, rate limiting, custom logic)
Summary¶
| Aspect | Continuous-Claude-v2 | fasthooks |
|---|---|---|
| What It Is | Session continuity system | Hook framework |
| Philosophy | Preserve context across clears | Build custom hook logic |
| Best For | Long-running projects | Custom policies |
| Language | TypeScript + Shell | Python |
| Blocking | PreToolUse only | Any event |
| Complexity | High (rich features) | Low (simple API) |
| Dependencies | Pre-bundled (none) | pip install |