npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mauribadnights/clooks

v0.6.3

Published

Persistent hook runtime for Claude Code — eliminates process spawning overhead and gives you observability

Readme

clooks

Persistent hook runtime for Claude Code. Eliminate cold starts. Get observability.

npm License: MIT

Documentation

Performance

| Metric | Without clooks | With clooks | Improvement | |--------|---------------|-------------|-------------| | Single hook invocation | ~34.6ms | ~0.31ms | 112x faster | | Full session (120 invocations) | ~3,986ms | ~23ms | 99% time saved | | 5 parallel handlers | ~424ms | ~96ms | 4.4x faster |

Benchmarked on Apple Silicon (M-series), Node v24.4.1. Run npm run bench to reproduce.

Installation

npm install -g @mauribadnights/clooks
clooks migrate    # migrates existing hooks, installs system service, installs clooks agent
clooks start

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.

How It Works

Architecture

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.

Quick Reference -- Commands

Daemon lifecycle:

| Command | Description | |---------|-------------| | clooks start | Start the daemon (-f foreground, --no-watch disable manifest watching) | | clooks stop | Stop the daemon | | clooks status | Show daemon status, uptime, handler count, service state | | clooks ensure-running | Start daemon if not running (used internally by SessionStart hook) |

Observability:

| Command | Description | |---------|-------------| | clooks stats | Interactive TUI for execution metrics (-t for plain text) | | clooks costs | LLM token usage and cost breakdown | | clooks doctor | Run diagnostic health checks |

Configuration:

| Command | Description | |---------|-------------| | clooks migrate | Convert settings.json command hooks to HTTP hooks, install service + agent | | clooks restore | Restore original settings.json from backup | | clooks sync | Sync settings.json with manifest (add missing HTTP hook entries) | | clooks init | Create default config directory and example manifest | | clooks update | Update clooks to latest version and refresh agent | | clooks rotate-token | Generate new auth token, update manifest + settings.json, hot-reload daemon |

Plugins:

| Command | Description | |---------|-------------| | clooks add <path> | Install a plugin from a local directory | | clooks remove <name> | Uninstall a plugin and its contributed handlers | | clooks plugins | List installed plugins and their handlers |

System service:

| Command | Description | |---------|-------------| | clooks service install | Install as system service (auto-start on login, auto-restart on crash) | | clooks service uninstall | Remove system service | | clooks service status | Show service status |

Configuration -- Manifest

Handlers are defined in ~/.clooks/manifest.yaml:

# Pre-fetch shared context once per event, available as $VARIABLES in LLM prompts
prefetch:
  - transcript        # last 50KB of session transcript
  - git_status        # git status --porcelain
  - git_diff          # git diff --stat (max 20KB)

handlers:
  PreToolUse:
    # Script handler -- spawns a shell command
    - id: safety-guard
      type: script
      command: node ~/hooks/guard.js
      filter: "Bash|Execute|!Read"      # OR logic, ! negates
      project: "*/my-project/*"         # only fire in matching cwd
      timeout: 3000
      enabled: true

    # LLM handler -- calls Anthropic Messages API (default backend)
    - id: code-review
      type: llm
      model: claude-haiku-4-5
      prompt: "Review this $TOOL_NAME call: $ARGUMENTS"
      batchGroup: analysis              # batched with other handlers in same group
      maxTokens: 512
      temperature: 0.5
      depends: [safety-guard]           # waits for safety-guard to complete first

    # Another LLM handler in the same batch group -- one API call for both
    - id: security-check
      type: llm
      model: claude-haiku-4-5
      prompt: "Check for security issues in $TOOL_NAME: $ARGUMENTS"
      batchGroup: analysis
      agent: "builder"                  # only fire in builder agent sessions

    # LLM handler -- spawns Claude Code CLI with an agent
    - id: agent-review
      type: llm
      backend: claude-code              # spawn claude CLI instead of API call
      llmAgent: security-reviewer       # --agent flag
      prompt: "Audit this change: $TOOL_NAME $ARGUMENTS"
      filter: "Bash|Write"

  UserPromptSubmit:
    # Inline handler -- imports a JS module in-process (no subprocess)
    - id: prompt-logger
      type: inline
      module: ~/.clooks/handlers/logger.js
      async: true                       # fire-and-forget, doesn't block response
      sessionIsolation: true            # reset state on SessionStart

  Stop:
    - id: session-summary
      type: llm
      model: claude-haiku-4-5
      prompt: "Summarize this session:\n$TRANSCRIPT\n\nGit changes:\n$GIT_DIFF"

settings:
  port: 7890
  logLevel: info                        # debug | info | warn | error
  authToken: your-token-here            # auto-generated by migrate/init
  # anthropicApiKey: sk-...             # or set ANTHROPIC_API_KEY env var

Handler Types

| Type | Overhead | Language | Use case | |------|----------|----------|----------| | script | ~5-35ms (subprocess) | Any (shell command) | Existing scripts, non-JS tools | | inline | <1ms (in-process) | JavaScript/TypeScript | Performance-critical handlers | | llm | Network-bound | Prompt template | AI-powered analysis, review, summarization |

script -- runs sh -c "command", pipes hook JSON to stdin, reads JSON from stdout.

inline -- imports a JS module and calls its default export. No subprocess overhead.

llm -- AI-powered analysis with $VARIABLE interpolation. Two backends: api (default, Anthropic API with batching and cost tracking) and claude-code (CLI spawn with agent support).

Handler Fields Reference

| Field | Type | Default | Applies to | Description | |-------|------|---------|------------|-------------| | id | string | required | all | Unique handler identifier | | type | string | required | all | script, inline, or llm | | command | string | required | script | Shell command to execute | | module | string | required | inline | Path to JS module with default export | | model | string | required | llm | claude-haiku-4-5, claude-sonnet-4-6, or claude-opus-4-6. Required for api backend, optional for claude-code. | | prompt | string | required | llm | Prompt template with $VARIABLE interpolation | | backend | string | api | llm | api (Anthropic API) or claude-code (CLI spawn) | | llmAgent | string | -- | llm | Agent name for claude-code backend (--agent flag) | | filter | string | -- | all | Keyword filter (see Filtering) | | project | string | -- | all | Glob pattern matched against cwd | | agent | string | -- | all | Only fire when session agent matches | | async | boolean | false | all | Fire-and-forget, don't block response | | depends | string[] | -- | all | Handler IDs to wait for before executing | | sessionIsolation | boolean | false | all | Reset handler state on SessionStart | | batchGroup | string | -- | llm | Group ID for batching into one API call (api backend only) | | maxTokens | number | 1024 | llm | Maximum output tokens | | temperature | number | 1.0 | llm | Sampling temperature | | timeout | number | 5000/30000 | all | Timeout in ms (5s default, 30s for llm) | | enabled | boolean | true | all | Disable without removing |

Scoped Execution

Handlers can be scoped to specific projects or agents:

- id: driffusion-lint
  type: script
  command: node ~/hooks/lint.js
  project: "*/Driffusion/*"     # only fires when cwd matches this glob

- id: builder-guard
  type: inline
  module: ~/hooks/guard.js
  agent: "builder"              # only fires in builder agent sessions

Both fields are optional. When omitted, the handler fires for all projects/agents.

Filtering

The filter field skips handlers based on keywords matched against the full JSON-serialized hook input (case-insensitive):

filter: "word1|word2"       # run if input contains word1 OR word2
filter: "!word"             # run unless input contains word
filter: "word1|!word2"     # run if word1 present AND word2 absent
- id: bash-guard
  type: script
  command: node ~/hooks/guard.js
  filter: "Bash|Execute|!Read"   # runs for Bash/Execute tools, never for Read

LLM Handlers

LLM handlers support two backends: api (default, Anthropic Messages API) and claude-code (spawns claude CLI).

API backend setup:

npm install @anthropic-ai/sdk    # peer dependency, required only for api backend
export ANTHROPIC_API_KEY=sk-...  # or set in manifest: settings.anthropicApiKey

Claude Code backend requires no API key or SDK — just the claude CLI installed and authenticated. Supports the llmAgent field for running prompts with a specific agent (--agent).

Prompt template variables:

| Variable | Source | Description | |----------|--------|-------------| | $TRANSCRIPT | Pre-fetched transcript file | Last 50KB of session transcript | | $GIT_STATUS | git status --porcelain | Current working tree status | | $GIT_DIFF | git diff --stat | Changed files summary (max 20KB) | | $ARGUMENTS | hook_input.tool_input | JSON-stringified tool arguments | | $TOOL_NAME | hook_input.tool_name | Name of the tool being called | | $PROMPT | hook_input.prompt | User's prompt (UserPromptSubmit only) | | $CWD | hook_input.cwd | Current working directory |

$TRANSCRIPT, $GIT_STATUS, and $GIT_DIFF require the corresponding key in prefetch. The others are always available from the hook input.

Batching (API backend only): 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. Claude Code backend handlers always execute individually.

Async Handlers

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.

- id: session-tracker
  type: inline
  module: ~/hooks/tracker.js
  async: true

Dependency Resolution

Handlers can declare dependencies with depends. clooks resolves them into topological execution waves -- handlers in the same wave run in parallel, waves execute sequentially.

- id: context-loader
  type: inline
  module: ~/hooks/context.js

- id: security-check
  type: llm
  model: claude-haiku-4-5
  prompt: "Check $TOOL_NAME given context: $CONTEXT"
  depends: [context-loader]    # runs in wave 2, after context-loader completes in wave 1

Pre-fetch

Fetch shared context once per hook event and make it available to all handlers via $VARIABLE interpolation in LLM prompts.

| Key | Source | Max size | Description | |-----|--------|----------|-------------| | transcript | transcript_path file | 50KB (tail) | Session conversation history | | git_status | git status --porcelain | unbounded | Working tree status | | git_diff | git diff --stat | 20KB | Changed files summary |

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.

Observability

Execution metrics -- clooks stats launches an interactive TUI by default. Use -t for plain text (also auto-selected when piped):

$ clooks stats -t

Event               Fires     Errors    Avg (ms)    Min (ms)    Max (ms)
------------------------------------------------------------------------
PreToolUse          47        0         1.2         0.8         3.1
Stop                12        0         2.4         1.1         5.6
UserPromptSubmit    12        1         1.8         0.9         4.2

Total fires: 71 | Total errors: 1 | Spawns saved: ~71

Diagnostics -- clooks doctor runs health checks on daemon, port, manifest, settings, and handler state:

$ clooks doctor

[pass] Daemon is running (PID 44721, uptime 2h 13m)
[pass] Port 7890 is responding
[pass] Manifest loaded: 4 handlers across 3 events
[pass] settings.json has HTTP hooks pointing to clooks
[pass] No handlers in circuit-breaker state
[warn] 1 handler error in last 24h (session-logger on Stop)

Cost tracking -- clooks costs shows LLM token usage and spend per handler and model:

$ clooks costs

LLM Cost Summary
  Total: $0.0142 (4,280 tokens)

  By Model:
    claude-haiku-4-5       $0.0142 (4,280 tokens)

  By Handler:
    code-review            $0.0089 (12 calls, avg 178 tokens)
    security-check         $0.0053 (12 calls, avg 178 tokens)

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.

System Service

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.

Plugin Development

Plugins package reusable sets of handlers. A plugin is any directory with a clooks-plugin.yaml:

# clooks-plugin.yaml
name: my-security-suite
version: 1.0.0
description: Security guards for tool calls
author: your-name

handlers:
  PreToolUse:
    - id: bash-guard
      type: inline
      module: $PLUGIN_DIR/handlers/bash-guard.js    # $PLUGIN_DIR resolves to plugin install path
      timeout: 3000
    - id: file-guard
      type: inline
      module: $PLUGIN_DIR/handlers/file-guard.js
      timeout: 2000

prefetch:
  - git_status

extras:
  skills: [security-audit]       # skill names this plugin provides
  agents: [security-reviewer]    # agent names this plugin provides
  readme: README.md              # path to plugin README (relative to plugin dir)

Installing and managing plugins:

clooks add ./my-security-suite     # install from local path
clooks remove my-security-suite    # uninstall
clooks plugins                     # list installed plugins + handlers

Handler IDs are automatically namespaced to the plugin (my-security-suite/bash-guard) to avoid collisions with user-defined handlers or other plugins.

Expert Agent

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.

Short-Circuit Chains

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.

Configuration Reference

| Item | Path / Value | |------|-------------| | Port | 7890 (default) | | Config directory | ~/.clooks/ | | Manifest | ~/.clooks/manifest.yaml | | Metrics | ~/.clooks/metrics.jsonl | | Costs | ~/.clooks/costs.jsonl | | Daemon log | ~/.clooks/daemon.log | | PID file | ~/.clooks/daemon.pid | | Plugins directory | ~/.clooks/plugins/ |

Contributing

Setup

git clone https://github.com/mauribadnights/clooks.git
cd clooks
npm install

Codebase layout

src/
  cli.ts          Command definitions (commander)
  server.ts       HTTP daemon — hook routing, auth, session management
  handlers.ts     Handler execution engine (script, inline, LLM)
  manifest.ts     Manifest loading and validation
  metrics.ts      Metrics collection and aggregation
  tui.ts          Interactive terminal dashboard (ANSI-based)
  llm.ts          LLM execution (Anthropic API + Claude Code CLI) and batching
  filter.ts       Keyword filter engine
  prefetch.ts     Pre-fetch context (transcript, git status/diff)
  plugin.ts       Plugin install/remove/list
  ...

tests/            Mirrors src/ — one test file per module
benchmarks/       Performance benchmarks
docs/             Architecture diagram and assets
hooks/            Built-in hook scripts
agents/           Built-in agent definitions

Development workflow

npm run build       # Compile TypeScript to dist/
npm test            # Run all tests (vitest)
npm run test:watch  # Watch mode
npm run bench       # Run performance benchmarks
npx tsc --noEmit    # Type-check without emitting

Pull request guidelines

  1. Fork the repo and create a feature branch from main
  2. Write tests for new functionality — tests are required for all PRs
  3. Ensure npm test passes and npx tsc --noEmit reports zero errors
  4. Write a clear PR description explaining what changed and why
  5. Keep PRs focused — one feature or fix per PR

Bug reports and feature requests

Open an issue at github.com/mauribadnights/clooks/issues with reproduction steps for bugs or a use-case description for features.

License

MIT