Summary
Provide a persistent state layer that hooks can read/write across invocations, enabling stateful behaviors.
Motivation
Hooks are currently fully stateless (stdin → stdout). However, many practical use cases require state:
- Track consecutive edit failures on the same file and block after N attempts
- Count Bash executions in a session and enforce a rate limit
- Reference the previous tool result in the next hook
- Accumulate token usage for cost tracking
Proposed API
import { store } from "@dawkinsuke/hooks/state"
cc.on("PreToolUse", "Bash", async (input) => {
const count = await store.get<number>("bash_count", 0)
if (count >= 50) {
throw new HookBlockError("Bash execution limit reached")
}
await store.set("bash_count", count + 1)
return input
})
Design Considerations
- Storage backend: File-based (JSON / SQLite) vs in-memory
- Scope: Per-session / per-project / global
- Concurrency: Locking strategy when multiple hooks read/write simultaneously
- TTL: Auto-expiring entries
- Testing integration: Swap in an in-memory store during
hx test
Summary
Provide a persistent state layer that hooks can read/write across invocations, enabling stateful behaviors.
Motivation
Hooks are currently fully stateless (stdin → stdout). However, many practical use cases require state:
Proposed API
Design Considerations
hx test