@mauribadnights/clooks 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # clooks
2
2
 
3
- **Persistent hook runtime for Claude Code.** Eliminate cold starts. Get observability.
3
+ Persistent hook runtime for Claude Code. Eliminate cold starts. Get observability.
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@mauribadnights/clooks.svg)](https://www.npmjs.com/package/@mauribadnights/clooks)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+ [![npm](https://img.shields.io/npm/v/@mauribadnights/clooks)](https://www.npmjs.com/package/@mauribadnights/clooks)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
7
 
8
8
  ## Performance
9
9
 
@@ -15,172 +15,206 @@
15
15
 
16
16
  > Benchmarked on Apple Silicon (M-series), Node v24.4.1. Run `npm run bench` to reproduce.
17
17
 
18
- ## The Problem
19
-
20
- Claude Code spawns a fresh process for every hook invocation. Each Node.js cold start costs 30-40ms. Power users with multiple hooks accumulate 100+ process spawns per session -- that is 4-6 seconds of pure overhead, with zero visibility into what your hooks are doing or how they fail.
21
-
22
- ## Quick Start
18
+ ## Installation
23
19
 
24
20
  ```bash
25
21
  npm install -g @mauribadnights/clooks
26
-
27
- # Option A: Migrate existing hooks automatically
28
- clooks migrate # converts command hooks to HTTP hooks + manifest
29
- clooks start # starts the daemon
30
-
31
- # Option B: Start fresh
32
- clooks init # creates ~/.clooks/manifest.yaml
22
+ clooks migrate # migrates existing hooks, installs system service, installs clooks agent
33
23
  clooks start
34
24
  ```
35
25
 
36
- That is it. Claude Code will now POST to your daemon instead of spawning processes.
26
+ `clooks migrate` converts your `settings.json` command hooks into HTTP hooks backed by the daemon, auto-installs a system service (launchd/systemd) for auto-start and crash recovery, and installs the `clooks` expert agent (`claude --agent clooks`). Starting fresh instead? Use `clooks init` to create a blank manifest.
37
27
 
38
28
  ## How It Works
39
29
 
40
- ```
41
- Claude Code clooks daemon (localhost:7890)
42
- | |
43
- |-- SessionStart ------> POST /hooks/SessionStart ------> [handler1, handler2]
44
- |-- UserPromptSubmit --> POST /hooks/UserPromptSubmit --> [handler3]
45
- |-- PreToolUse (x50) --> POST /hooks/PreToolUse --------> [handler4, handler5]
46
- |-- Stop --------------> POST /hooks/Stop ---------------> [handler6]
47
- | |
48
- |<-------------- JSON responses ---------|
49
- ```
30
+ ![Architecture](docs/architecture.png)
50
31
 
51
- One persistent process. Zero cold starts. Full observability.
32
+ One persistent HTTP server replaces per-invocation process spawning. Claude Code POSTs hook events to the daemon, which dispatches to handlers defined in `~/.clooks/manifest.yaml`. Handlers that fail 3 times consecutively are auto-disabled.
52
33
 
53
- After `clooks migrate`, your `settings.json` is rewritten so that `SessionStart` runs a single command hook (`clooks ensure-running`) and all other hooks become HTTP POSTs. The daemon loads handlers from `~/.clooks/manifest.yaml` and dispatches them in parallel per event. Handlers that fail 3 times consecutively are auto-disabled to prevent cascading failures.
34
+ ## Quick Reference -- Commands
54
35
 
55
- ## Commands
36
+ **Daemon lifecycle:**
56
37
 
57
38
  | Command | Description |
58
39
  |---------|-------------|
59
- | `clooks start` | Start the daemon (background by default, `--foreground` for debug) |
40
+ | `clooks start` | Start the daemon (`-f` foreground, `--no-watch` disable manifest watching) |
60
41
  | `clooks stop` | Stop the daemon |
61
- | `clooks status` | Show daemon status, uptime, and handler count |
62
- | `clooks stats` | Show hook execution metrics (fires, errors, latency) |
63
- | `clooks migrate` | Convert `settings.json` command hooks to HTTP hooks |
64
- | `clooks restore` | Restore original `settings.json` from backup |
42
+ | `clooks status` | Show daemon status, uptime, handler count, service state |
43
+ | `clooks ensure-running` | Start daemon if not running (used internally by SessionStart hook) |
44
+
45
+ **Observability:**
46
+
47
+ | Command | Description |
48
+ |---------|-------------|
49
+ | `clooks stats` | Interactive TUI for execution metrics (`-t` for plain text) |
50
+ | `clooks costs` | LLM token usage and cost breakdown |
65
51
  | `clooks doctor` | Run diagnostic health checks |
52
+
53
+ **Configuration:**
54
+
55
+ | Command | Description |
56
+ |---------|-------------|
57
+ | `clooks migrate` | Convert `settings.json` command hooks to HTTP hooks, install service + agent |
58
+ | `clooks restore` | Restore original `settings.json` from backup |
59
+ | `clooks sync` | Sync `settings.json` with manifest (add missing HTTP hook entries) |
66
60
  | `clooks init` | Create default config directory and example manifest |
67
- | `clooks ensure-running` | Start daemon if not already running (used by SessionStart hook) |
61
+ | `clooks update` | Update clooks to latest version and refresh agent |
62
+ | `clooks rotate-token` | Generate new auth token, update manifest + settings.json, hot-reload daemon |
63
+
64
+ **Plugins:**
65
+
66
+ | Command | Description |
67
+ |---------|-------------|
68
68
  | `clooks add <path>` | Install a plugin from a local directory |
69
69
  | `clooks remove <name>` | Uninstall a plugin and its contributed handlers |
70
70
  | `clooks plugins` | List installed plugins and their handlers |
71
- | `clooks rotate-token` | Generate a new auth token, update manifest + settings.json, hot-reload daemon |
72
- | `clooks costs` | Show LLM token usage and cost breakdown |
73
71
 
74
- ## Manifest Format
72
+ **System service:**
73
+
74
+ | Command | Description |
75
+ |---------|-------------|
76
+ | `clooks service install` | Install as system service (auto-start on login, auto-restart on crash) |
77
+ | `clooks service uninstall` | Remove system service |
78
+ | `clooks service status` | Show service status |
79
+
80
+ ## Configuration -- Manifest
75
81
 
76
82
  Handlers are defined in `~/.clooks/manifest.yaml`:
77
83
 
78
84
  ```yaml
85
+ # Pre-fetch shared context once per event, available as $VARIABLES in LLM prompts
86
+ prefetch:
87
+ - transcript # last 50KB of session transcript
88
+ - git_status # git status --porcelain
89
+ - git_diff # git diff --stat (max 20KB)
90
+
79
91
  handlers:
80
92
  PreToolUse:
93
+ # Script handler -- spawns a shell command
81
94
  - id: safety-guard
82
- type: script # runs a shell command
95
+ type: script
83
96
  command: node ~/hooks/guard.js
97
+ filter: "Bash|Execute|!Read" # OR logic, ! negates
98
+ project: "*/my-project/*" # only fire in matching cwd
84
99
  timeout: 3000
85
100
  enabled: true
86
101
 
87
- - id: context-injector
88
- type: inline # imports a JS module directly (no subprocess)
89
- module: ~/hooks/context.js
90
- timeout: 2000
102
+ # LLM handler -- calls Anthropic Messages API
103
+ - id: code-review
104
+ type: llm
105
+ model: claude-haiku-4-5
106
+ prompt: "Review this $TOOL_NAME call: $ARGUMENTS"
107
+ batchGroup: analysis # batched with other handlers in same group
108
+ maxTokens: 512
109
+ temperature: 0.5
110
+ depends: [safety-guard] # waits for safety-guard to complete first
111
+
112
+ # Another LLM handler in the same batch group -- one API call for both
113
+ - id: security-check
114
+ type: llm
115
+ model: claude-haiku-4-5
116
+ prompt: "Check for security issues in $TOOL_NAME: $ARGUMENTS"
117
+ batchGroup: analysis
118
+ agent: "builder" # only fire in builder agent sessions
119
+
120
+ UserPromptSubmit:
121
+ # Inline handler -- imports a JS module in-process (no subprocess)
122
+ - id: prompt-logger
123
+ type: inline
124
+ module: ~/.clooks/handlers/logger.js
125
+ async: true # fire-and-forget, doesn't block response
126
+ sessionIsolation: true # reset state on SessionStart
91
127
 
92
128
  Stop:
93
- - id: session-logger
94
- type: script
95
- command: ~/hooks/log-session.sh
129
+ - id: session-summary
130
+ type: llm
131
+ model: claude-haiku-4-5
132
+ prompt: "Summarize this session:\n$TRANSCRIPT\n\nGit changes:\n$GIT_DIFF"
96
133
 
97
134
  settings:
98
135
  port: 7890
99
- logLevel: info
136
+ logLevel: info # debug | info | warn | error
137
+ authToken: your-token-here # auto-generated by migrate/init
138
+ # anthropicApiKey: sk-... # or set ANTHROPIC_API_KEY env var
100
139
  ```
101
140
 
102
- **Handler types:**
103
- - `script` -- runs a shell command, pipes hook JSON to stdin, reads JSON from stdout.
104
- - `inline` -- imports a JS module and calls its default export. Faster; no subprocess overhead.
105
- - `llm` -- calls Anthropic Messages API. Supports prompt templates, batching, and cost tracking. *(v0.2+)*
141
+ ## Handler Types
106
142
 
107
- ## Observability
143
+ | Type | Overhead | Language | Use case |
144
+ |------|----------|----------|----------|
145
+ | `script` | ~5-35ms (subprocess) | Any (shell command) | Existing scripts, non-JS tools |
146
+ | `inline` | <1ms (in-process) | JavaScript/TypeScript | Performance-critical handlers |
147
+ | `llm` | Network-bound | Prompt template | AI-powered analysis, review, summarization |
108
148
 
109
- ### Execution Metrics
149
+ **script** -- runs `sh -c "command"`, pipes hook JSON to stdin, reads JSON from stdout.
110
150
 
111
- ```
112
- $ clooks stats
151
+ **inline** -- imports a JS module and calls its default export. No subprocess overhead.
113
152
 
114
- Event Fires Errors Avg (ms) Min (ms) Max (ms)
115
- ------------------------------------------------------------------------
116
- PreToolUse 47 0 1.2 0.8 3.1
117
- Stop 12 0 2.4 1.1 5.6
118
- UserPromptSubmit 12 1 1.8 0.9 4.2
153
+ **llm** -- calls Anthropic Messages API with `$VARIABLE` interpolation. Supports batching and cost tracking.
119
154
 
120
- Total fires: 71 | Total errors: 1 | Spawns saved: ~71
121
- ```
155
+ ## Handler Fields Reference
122
156
 
123
- ### Diagnostics
157
+ | Field | Type | Default | Applies to | Description |
158
+ |-------|------|---------|------------|-------------|
159
+ | `id` | string | required | all | Unique handler identifier |
160
+ | `type` | string | required | all | `script`, `inline`, or `llm` |
161
+ | `command` | string | required | script | Shell command to execute |
162
+ | `module` | string | required | inline | Path to JS module with default export |
163
+ | `model` | string | required | llm | `claude-haiku-4-5`, `claude-sonnet-4-6`, or `claude-opus-4-6` |
164
+ | `prompt` | string | required | llm | Prompt template with `$VARIABLE` interpolation |
165
+ | `filter` | string | -- | all | Keyword filter (see Filtering) |
166
+ | `project` | string | -- | all | Glob pattern matched against cwd |
167
+ | `agent` | string | -- | all | Only fire when session agent matches |
168
+ | `async` | boolean | `false` | all | Fire-and-forget, don't block response |
169
+ | `depends` | string[] | -- | all | Handler IDs to wait for before executing |
170
+ | `sessionIsolation` | boolean | `false` | all | Reset handler state on SessionStart |
171
+ | `batchGroup` | string | -- | llm | Group ID for batching into one API call |
172
+ | `maxTokens` | number | `1024` | llm | Maximum output tokens |
173
+ | `temperature` | number | `1.0` | llm | Sampling temperature |
174
+ | `timeout` | number | `5000`/`30000` | all | Timeout in ms (5s default, 30s for llm) |
175
+ | `enabled` | boolean | `true` | all | Disable without removing |
124
176
 
125
- ```
126
- $ clooks doctor
177
+ ## Scoped Execution
127
178
 
128
- [pass] Daemon is running (PID 44721, uptime 2h 13m)
129
- [pass] Port 7890 is responding
130
- [pass] Manifest loaded: 4 handlers across 3 events
131
- [pass] settings.json has HTTP hooks pointing to clooks
132
- [pass] No handlers in circuit-breaker state
133
- [warn] 1 handler error in last 24h (session-logger on Stop)
134
- ```
135
-
136
- ## Comparison
179
+ Handlers can be scoped to specific projects or agents:
137
180
 
138
- | | Without clooks | With clooks |
139
- |---|---|---|
140
- | **Process model** | New process per hook invocation | One persistent HTTP server |
141
- | **Cold start overhead** | 30-40ms per invocation | 0ms (already running) |
142
- | **State management** | Stateless -- each invocation starts fresh | Persistent -- share state across invocations |
143
- | **Observability** | None | Metrics, stats, logs, doctor diagnostics |
144
- | **Error handling** | Silent failures | Auto-disable after 3 consecutive failures |
145
-
146
- ## Configuration Reference
181
+ ```yaml
182
+ - id: driffusion-lint
183
+ type: script
184
+ command: node ~/hooks/lint.js
185
+ project: "*/Driffusion/*" # only fires when cwd matches this glob
186
+
187
+ - id: builder-guard
188
+ type: inline
189
+ module: ~/hooks/guard.js
190
+ agent: "builder" # only fires in builder agent sessions
191
+ ```
147
192
 
148
- | Option | Default | Description |
149
- |--------|---------|-------------|
150
- | Port | `7890` | HTTP server port |
151
- | Config directory | `~/.clooks/` | Root configuration directory |
152
- | Manifest | `~/.clooks/manifest.yaml` | Handler definitions |
153
- | Metrics | `~/.clooks/metrics.jsonl` | Execution metrics log |
154
- | Daemon log | `~/.clooks/daemon.log` | Server output log |
155
- | PID file | `~/.clooks/daemon.pid` | Process ID file |
193
+ Both fields are optional. When omitted, the handler fires for all projects/agents.
156
194
 
157
- ## v0.2 Features
195
+ ## Filtering
158
196
 
159
- ### LLM Handlers
197
+ The `filter` field skips handlers based on keywords matched against the full JSON-serialized hook input (case-insensitive):
160
198
 
161
- Call the Anthropic Messages API directly from your manifest. Handlers with the same `batchGroup` are combined into a single API call, saving tokens and latency.
199
+ ```
200
+ filter: "word1|word2" # run if input contains word1 OR word2
201
+ filter: "!word" # run unless input contains word
202
+ filter: "word1|!word2" # run if word1 present AND word2 absent
203
+ ```
162
204
 
163
205
  ```yaml
164
- handlers:
165
- PreToolUse:
166
- - id: code-review
167
- type: llm
168
- model: claude-haiku-4-5
169
- prompt: "Review this tool call for $TOOL_NAME with args: $ARGUMENTS"
170
- batchGroup: analysis
171
- timeout: 15000
172
-
173
- - id: security-check
174
- type: llm
175
- model: claude-haiku-4-5
176
- prompt: "Check for security issues in $TOOL_NAME call: $ARGUMENTS"
177
- batchGroup: analysis # batched with code-review into one API call
206
+ - id: bash-guard
207
+ type: script
208
+ command: node ~/hooks/guard.js
209
+ filter: "Bash|Execute|!Read" # runs for Bash/Execute tools, never for Read
178
210
  ```
179
211
 
212
+ ## LLM Handlers
213
+
180
214
  **Setup:**
181
215
 
182
216
  ```bash
183
- npm install @anthropic-ai/sdk # peer dependency, only needed for llm handlers
217
+ npm install @anthropic-ai/sdk # peer dependency, required only for llm handlers
184
218
  export ANTHROPIC_API_KEY=sk-... # or set in manifest: settings.anthropicApiKey
185
219
  ```
186
220
 
@@ -196,64 +230,40 @@ export ANTHROPIC_API_KEY=sk-... # or set in manifest: settings.anthropicApiKey
196
230
  | `$PROMPT` | `hook_input.prompt` | User's prompt (UserPromptSubmit only) |
197
231
  | `$CWD` | `hook_input.cwd` | Current working directory |
198
232
 
199
- **LLM handler options:**
200
-
201
- | Field | Type | Default | Description |
202
- |-------|------|---------|-------------|
203
- | `model` | string | required | `claude-haiku-4-5`, `claude-sonnet-4-6`, or `claude-opus-4-6` |
204
- | `prompt` | string | required | Prompt template with `$VARIABLE` interpolation |
205
- | `batchGroup` | string | optional | Group ID -- handlers with same group make one API call |
206
- | `maxTokens` | number | `1024` | Maximum output tokens |
207
- | `temperature` | number | `1.0` | Sampling temperature |
208
- | `filter` | string | optional | Keyword filter (see Filtering) |
209
- | `timeout` | number | `30000` | Timeout in milliseconds |
210
-
211
- **How batching works:**
212
-
213
- When multiple LLM handlers share a `batchGroup` on the same event, clooks combines their prompts into a single multi-task API call and splits the structured response back to each handler. This means 3 Haiku calls become 1, saving ~2/3 of the input token cost and eliminating 2 round-trips.
233
+ `$TRANSCRIPT`, `$GIT_STATUS`, and `$GIT_DIFF` require the corresponding key in `prefetch`. The others are always available from the hook input.
214
234
 
215
- ### Intelligent Filtering
235
+ **Batching:** Handlers sharing a `batchGroup` on the same event are combined into a single API call. Three Haiku calls become one, saving ~2/3 of input token cost and eliminating two round-trips. Batch groups are scoped per session to prevent cross-session contamination.
216
236
 
217
- Skip handlers based on keywords. The `filter` field works on **all handler types** -- script, inline, and llm.
218
-
219
- **Filter syntax:**
220
-
221
- ```
222
- filter: "word1|word2" # run if input contains word1 OR word2
223
- filter: "!word" # run unless input contains word
224
- filter: "word1|!word2" # run if word1 present AND word2 absent
225
- ```
237
+ ## Async Handlers
226
238
 
227
- Matching is case-insensitive against the full JSON-serialized hook input.
239
+ Handlers with `async: true` execute fire-and-forget -- they run in the background and do not block Claude's response. Use this for logging, analytics, or any work that does not need to inject context back into the session.
228
240
 
229
241
  ```yaml
230
- handlers:
231
- PreToolUse:
232
- - id: bash-guard
233
- type: script
234
- command: node ~/hooks/guard.js
235
- filter: "Bash|Execute|!Read" # runs for Bash/Execute, never for Read
242
+ - id: session-tracker
243
+ type: inline
244
+ module: ~/hooks/tracker.js
245
+ async: true
236
246
  ```
237
247
 
238
- ### Shared Context Pre-fetch
248
+ ## Dependency Resolution
239
249
 
240
- Fetch transcript, git status, or git diff once per hook event and share across all handlers. Avoids redundant I/O when multiple handlers need the same data. Use `$VARIABLE` interpolation in LLM prompts.
250
+ Handlers can declare dependencies with `depends`. clooks resolves them into topological execution waves -- handlers in the same wave run in parallel, waves execute sequentially.
241
251
 
242
252
  ```yaml
243
- prefetch:
244
- - transcript
245
- - git_status
246
- - git_diff
247
-
248
- handlers:
249
- Stop:
250
- - id: session-summary
251
- type: llm
252
- model: claude-haiku-4-5
253
- prompt: "Summarize this session:\n$TRANSCRIPT\n\nGit changes:\n$GIT_DIFF"
253
+ - id: context-loader
254
+ type: inline
255
+ module: ~/hooks/context.js
256
+
257
+ - id: security-check
258
+ type: llm
259
+ model: claude-haiku-4-5
260
+ prompt: "Check $TOOL_NAME given context: $CONTEXT"
261
+ depends: [context-loader] # runs in wave 2, after context-loader completes in wave 1
254
262
  ```
255
263
 
256
- **Available prefetch keys:**
264
+ ## Pre-fetch
265
+
266
+ Fetch shared context once per hook event and make it available to all handlers via `$VARIABLE` interpolation in LLM prompts.
257
267
 
258
268
  | Key | Source | Max size | Description |
259
269
  |-----|--------|----------|-------------|
@@ -261,11 +271,38 @@ handlers:
261
271
  | `git_status` | `git status --porcelain` | unbounded | Working tree status |
262
272
  | `git_diff` | `git diff --stat` | 20KB | Changed files summary |
263
273
 
264
- Pre-fetched data is cached for the duration of a single event dispatch. Errors on individual keys are silently caught -- a failed `git_status` won't prevent `transcript` from loading.
274
+ Pre-fetched data is cached for the duration of a single event dispatch. Errors on individual keys are silently caught -- a failed `git_status` does not prevent `transcript` from loading.
265
275
 
266
- ### Cost Tracking
276
+ ## Observability
267
277
 
268
- Track LLM token usage and costs per handler and model.
278
+ **Execution metrics** -- `clooks stats` launches an interactive TUI by default. Use `-t` for plain text (also auto-selected when piped):
279
+
280
+ ```
281
+ $ clooks stats -t
282
+
283
+ Event Fires Errors Avg (ms) Min (ms) Max (ms)
284
+ ------------------------------------------------------------------------
285
+ PreToolUse 47 0 1.2 0.8 3.1
286
+ Stop 12 0 2.4 1.1 5.6
287
+ UserPromptSubmit 12 1 1.8 0.9 4.2
288
+
289
+ Total fires: 71 | Total errors: 1 | Spawns saved: ~71
290
+ ```
291
+
292
+ **Diagnostics** -- `clooks doctor` runs health checks on daemon, port, manifest, settings, and handler state:
293
+
294
+ ```
295
+ $ clooks doctor
296
+
297
+ [pass] Daemon is running (PID 44721, uptime 2h 13m)
298
+ [pass] Port 7890 is responding
299
+ [pass] Manifest loaded: 4 handlers across 3 events
300
+ [pass] settings.json has HTTP hooks pointing to clooks
301
+ [pass] No handlers in circuit-breaker state
302
+ [warn] 1 handler error in last 24h (session-logger on Stop)
303
+ ```
304
+
305
+ **Cost tracking** -- `clooks costs` shows LLM token usage and spend per handler and model:
269
306
 
270
307
  ```
271
308
  $ clooks costs
@@ -281,35 +318,44 @@ LLM Cost Summary
281
318
  security-check $0.0053 (12 calls, avg 178 tokens)
282
319
  ```
283
320
 
284
- - Costs are persisted to `~/.clooks/costs.jsonl`
285
- - Built-in pricing (per million tokens): Haiku ($0.80 / $4.00), Sonnet ($3.00 / $15.00), Opus ($15.00 / $75.00)
286
- - Batching savings are estimated based on shared input tokens
287
- - Cost data also appears in `clooks stats` when LLM handlers have been used
321
+ Built-in pricing (per million tokens): Haiku ($0.80 / $4.00), Sonnet ($3.00 / $15.00), Opus ($15.00 / $75.00). Costs persist to `~/.clooks/costs.jsonl`.
322
+
323
+ ## System Service
288
324
 
289
- ## v0.3 Features
325
+ `clooks service install` creates a platform-native service (launchd on macOS, systemd on Linux) that starts the daemon on login and restarts it on crash. `clooks migrate` and `clooks init` install the service automatically. Use `clooks service status` to check and `clooks service uninstall` to remove.
290
326
 
291
- ### Plugin System
327
+ ## Plugin Development
292
328
 
293
- Plugins let you package and share sets of handlers. A plugin is any directory with a `clooks-plugin.yaml` spec:
329
+ Plugins package reusable sets of handlers. A plugin is any directory with a `clooks-plugin.yaml`:
294
330
 
295
331
  ```yaml
296
332
  # clooks-plugin.yaml
297
333
  name: my-security-suite
298
334
  version: 1.0.0
299
335
  description: Security guards for tool calls
336
+ author: your-name
337
+
300
338
  handlers:
301
339
  PreToolUse:
302
340
  - id: bash-guard
303
341
  type: inline
304
- module: ./handlers/bash-guard.js
342
+ module: $PLUGIN_DIR/handlers/bash-guard.js # $PLUGIN_DIR resolves to plugin install path
305
343
  timeout: 3000
306
344
  - id: file-guard
307
345
  type: inline
308
- module: ./handlers/file-guard.js
346
+ module: $PLUGIN_DIR/handlers/file-guard.js
309
347
  timeout: 2000
348
+
349
+ prefetch:
350
+ - git_status
351
+
352
+ extras:
353
+ skills: [security-audit] # skill names this plugin provides
354
+ agents: [security-reviewer] # agent names this plugin provides
355
+ readme: README.md # path to plugin README (relative to plugin dir)
310
356
  ```
311
357
 
312
- Install, remove, and list plugins:
358
+ **Installing and managing plugins:**
313
359
 
314
360
  ```bash
315
361
  clooks add ./my-security-suite # install from local path
@@ -317,55 +363,84 @@ clooks remove my-security-suite # uninstall
317
363
  clooks plugins # list installed plugins + handlers
318
364
  ```
319
365
 
320
- Handler IDs are namespaced to the plugin (`my-security-suite:bash-guard`) to avoid collisions with user-defined handlers or other plugins.
321
-
322
- ### Dependency Resolution
323
-
324
- Handlers can declare dependencies on other handlers using the `depends` field. clooks resolves dependencies into topological execution waves -- handlers in the same wave run in parallel, waves execute sequentially.
366
+ Handler IDs are automatically namespaced to the plugin (`my-security-suite/bash-guard`) to avoid collisions with user-defined handlers or other plugins.
325
367
 
326
- ```yaml
327
- handlers:
328
- PreToolUse:
329
- - id: context-loader
330
- type: inline
331
- module: ~/hooks/context.js
368
+ ## Expert Agent
332
369
 
333
- - id: security-check
334
- type: llm
335
- model: claude-haiku-4-5
336
- prompt: "Check $TOOL_NAME for issues given context: $CONTEXT"
337
- depends: [context-loader] # waits for context-loader to finish first
338
- ```
370
+ clooks ships with an expert agent that understands the full architecture, configuration, and troubleshooting workflow. It is auto-installed and auto-updated by `clooks migrate`, `clooks init`, and `clooks update`. Invoke it with `claude --agent clooks`.
339
371
 
340
- In this example, `context-loader` runs in wave 1, and `security-check` runs in wave 2 after it completes. Handlers with no dependencies (or whose dependencies are already satisfied) run in parallel within the same wave.
372
+ ## Short-Circuit Chains
341
373
 
342
- ### Short-Circuit Chains
374
+ When a `PreToolUse` handler returns a deny decision, clooks automatically skips the corresponding `PostToolUse` handlers for that tool call. Deny results are cached with a 30-second TTL, so repeated calls to the same tool with the same arguments short-circuit without re-evaluating handlers.
343
375
 
344
- When a `PreToolUse` handler returns a deny decision, clooks automatically skips the corresponding `PostToolUse` handlers for that tool call. This avoids wasted work (and wasted LLM calls) on tool invocations that were blocked.
376
+ ## Configuration Reference
345
377
 
346
- Deny results are cached with a 30-second TTL, so repeated calls to the same tool with the same arguments short-circuit without re-evaluating handlers.
378
+ | Item | Path / Value |
379
+ |------|-------------|
380
+ | Port | `7890` (default) |
381
+ | Config directory | `~/.clooks/` |
382
+ | Manifest | `~/.clooks/manifest.yaml` |
383
+ | Metrics | `~/.clooks/metrics.jsonl` |
384
+ | Costs | `~/.clooks/costs.jsonl` |
385
+ | Daemon log | `~/.clooks/daemon.log` |
386
+ | PID file | `~/.clooks/daemon.pid` |
387
+ | Plugins directory | `~/.clooks/plugins/` |
347
388
 
348
- ### Other v0.3 Improvements
389
+ ## Contributing
349
390
 
350
- - **Auth token rotation:** `clooks rotate-token` generates a new token, updates manifest and settings.json, and hot-reloads the daemon -- no restart required.
351
- - **Health endpoint split:** `/health` is now public (returns `{ status: "ok" }` only). `/health/detail` requires auth and returns uptime, handler count, and plugin list.
352
- - **Rate limiting on auth failures:** In-memory rate limiter rejects with 429 after repeated failed auth attempts within a time window. Resets on successful auth.
353
- - **Session-scoped LLM batch groups:** Batch groups are now scoped to `{batchGroup}:{session_id}`, preventing cross-session batching violations.
354
- - **Manifest reload resets handler state:** Reloading the manifest now diffs old vs new handlers and resets session-isolated state for changed or new handlers.
391
+ ### Setup
355
392
 
356
- ## Roadmap
393
+ ```bash
394
+ git clone https://github.com/mauribadnights/clooks.git
395
+ cd clooks
396
+ npm install
397
+ ```
357
398
 
358
- - **v0.4:** Visual dashboard for hook management and metrics
399
+ ### Codebase layout
359
400
 
360
- ## Contributing
401
+ ```
402
+ src/
403
+ cli.ts Command definitions (commander)
404
+ server.ts HTTP daemon — hook routing, auth, session management
405
+ handlers.ts Handler execution engine (script, inline, LLM)
406
+ manifest.ts Manifest loading and validation
407
+ metrics.ts Metrics collection and aggregation
408
+ tui.ts Interactive terminal dashboard (ANSI-based)
409
+ llm.ts Anthropic API integration and batching
410
+ filter.ts Keyword filter engine
411
+ prefetch.ts Pre-fetch context (transcript, git status/diff)
412
+ plugin.ts Plugin install/remove/list
413
+ ...
414
+
415
+ tests/ Mirrors src/ — one test file per module
416
+ benchmarks/ Performance benchmarks
417
+ docs/ Architecture diagram and assets
418
+ hooks/ Built-in hook scripts
419
+ agents/ Built-in agent definitions
420
+ ```
361
421
 
362
- Issues and pull requests are welcome. Run the test suite before submitting:
422
+ ### Development workflow
363
423
 
364
424
  ```bash
365
- npm test
366
- npm run bench
425
+ npm run build # Compile TypeScript to dist/
426
+ npm test # Run all tests (vitest)
427
+ npm run test:watch # Watch mode
428
+ npm run bench # Run performance benchmarks
429
+ npx tsc --noEmit # Type-check without emitting
367
430
  ```
368
431
 
432
+ ### Pull request guidelines
433
+
434
+ 1. Fork the repo and create a feature branch from `main`
435
+ 2. Write tests for new functionality — tests are required for all PRs
436
+ 3. Ensure `npm test` passes and `npx tsc --noEmit` reports zero errors
437
+ 4. Write a clear PR description explaining **what** changed and **why**
438
+ 5. Keep PRs focused — one feature or fix per PR
439
+
440
+ ### Bug reports and feature requests
441
+
442
+ Open an issue at [github.com/mauribadnights/clooks/issues](https://github.com/mauribadnights/clooks/issues) with reproduction steps for bugs or a use-case description for features.
443
+
369
444
  ## License
370
445
 
371
446
  MIT
package/dist/cli.js CHANGED
@@ -21,7 +21,7 @@ const program = new commander_1.Command();
21
21
  program
22
22
  .name('clooks')
23
23
  .description('Persistent hook runtime for Claude Code')
24
- .version('0.4.0');
24
+ .version('0.4.1');
25
25
  // --- start ---
26
26
  program
27
27
  .command('start')
package/dist/server.js CHANGED
@@ -243,6 +243,7 @@ function createServer(manifest, metrics) {
243
243
  usage: result.usage,
244
244
  cost_usd: result.cost_usd,
245
245
  session_id: input.session_id,
246
+ agent_type: currentAgent,
246
247
  });
247
248
  if (result.usage && result.cost_usd !== undefined && result.cost_usd > 0) {
248
249
  const handlerConfig = allHandlerConfigs.find(h => h.id === result.id);