Skip to main content

Hook system and MCP tool server for Claude Code agents

Project description

agentihooks

Standalone License: MIT CI Python 3.11+ Docs

Hook system and MCP tool server for Claude Code. Intercepts every lifecycle event (session start/end, tool use, prompts, stops), provides MCP tools for external services, and includes a Token Control Layer that monitors context window usage, truncates verbose output, deduplicates file reads, and warns before quota exhaustion.

Full documentation: the-cloud-clock-work.github.io/agentihooks

Architecture

Claude Code
  |
  |-- Hook Events (stdin JSON) --> python -m hooks --> hook_manager.py
  |     SessionStart, PreToolUse,       |
  |     PostToolUse, Stop, ...         |-- transcript logging
  |     (10 events total)              |-- tool error memory
  |                                    |-- token control layer
  |                                    |-- metrics parsing
  |
  |-- statusLine (native setting) --> python -m hooks.statusline
  |     pipes JSON on every turn       --> 2-3 line status bar (ctx%, burn rate, cost, git)
  |
  +-- MCP Tools --> python -m hooks.mcp --> category modules
        aws, email, messaging,               --> hooks/integrations/*
        database, compute, ...

Quick Start

Requirement: uv must be installed.

git clone https://github.com/The-Cloud-Clock-Work/agentihooks
cd agentihooks

# 1. Create the dedicated venv and install everything
uv venv ~/.agentihooks/.venv
uv pip install --python ~/.agentihooks/.venv/bin/python -e ".[all]"

# 2. Install hooks + settings + MCP into ~/.claude
agentihooks init

agentihooks init wires hooks into ~/.claude/settings.json, symlinks skills/agents/commands/rules, merges MCP servers into ~/.claude.json, installs the CLI globally, and auto-starts background daemons. Every hook command is written with the Python that ran the installer, so all subprocesses find the right packages regardless of which shell or venv is active.

Re-run any time -- it is idempotent. See Installation for a full walkthrough.

CLI

# Install / re-install
agentihooks init                             # global install with default profile
agentihooks init --bundle ~/my-tools         # first-time: link bundle + install
agentihooks init --profile coding            # use a specific profile
agentihooks init --repo /path/to/repo        # per-repo config

# Launch claude with profile flags
agentihooks claude                           # reads profile.yml -> CLI flags
agenti                                       # alias (after source ~/.bashrc)

# Uninstall
agentihooks uninstall [--yes]                # remove everything

# Multi-account quota watcher
agentihooks quota auth <name>                # add/update account
agentihooks quota list                       # show all accounts
agentihooks quota switch [name]              # switch active account
agentihooks quota restart                    # stop + start daemon
agentihooks quota status                     # show current usage
agentihooks quota logs                       # tail daemon log
agentihooks quota stop                       # kill daemon
agentihooks quota remove <name>              # delete account

# Bundle management
agentihooks bundle list                      # show linked bundle + profiles
agentihooks bundle pull                      # git pull the linked bundle
agentihooks bundle pull --rebase             # git pull --rebase
agentihooks bundle link ~/dev/my-tools       # link a bundle directory
agentihooks bundle unlink                    # unlink current bundle

# Sync daemon (auto-propagation)
agentihooks daemon start                     # start background daemon (60s poll)
agentihooks daemon status                    # show targets + watched files
agentihooks daemon logs                      # tail daemon log
agentihooks daemon stop                      # kill daemon

# Status & diagnostics
agentihooks status                           # full system health + MCP fleet + guardrails + quota

# Token optimization
agentihooks lint-claude [path]               # analyze CLAUDE.md token cost
agentihooks extract-skill "Section" --name x # extract section to on-demand skill
agentihooks mcp report                       # MCP surface area report

# Utilities
agentihooks ignore [path] [--force]          # create .claudeignore
agentihooks --list-profiles                  # show available profiles
agentihooks --query                          # print active profile name

CLI output uses colored markers: [OK] green, [--] dim, [!!] yellow, [RM] red.

What init Does

  1. Links bundle (if --bundle provided)
  2. Merges settings: settings.base.json -> each profile's settings.overrides.json (chained) -> OTEL config
  3. Symlinks skills, agents, commands, and rules (3-layer merge, additive across chain)
  4. Writes CLAUDE.md to ~/.claude/CLAUDE.md (copy for single profile, concatenated for chains)
  5. Installs MCP servers (hooks-utils + bundle + profile)
  6. Applies MCP blacklist to all registered projects
  7. Installs CLI globally via uv tool
  8. Auto-starts quota daemon (if accounts exist) and sync daemon
  9. Writes bashrc block (agentienv shell function + agenti alias)

Profiles

Profiles mirror the Claude Code project structure:

profiles/<name>/
|-- CLAUDE.md                    # system prompt (-> ~/.claude/CLAUDE.md)
|-- profile.yml                  # agentihooks metadata + claude flags
+-- .claude/
    |-- settings.overrides.json  # merged into ~/.claude/settings.json
    |-- .mcp.json                # profile MCP servers
    |-- skills/                  # -> ~/.claude/skills/
    |-- agents/                  # -> ~/.claude/agents/
    |-- commands/                # -> ~/.claude/commands/
    +-- rules/                   # -> ~/.claude/rules/

Built-in profiles: default, coding, admin. Bundle profiles are discovered automatically.

3-layer merge: agentihooks built-in -> bundle global .claude/ -> profile-specific .claude/. Applies to skills, agents, commands, rules, and MCP servers.

Switch profiles: agentihooks init --profile <name>. Chain profiles: agentihooks init --profile coding,colt. List all: agentihooks --list-profiles.

Profile chaining: Comma-separated profiles are applied left to right. Settings deep-merge sequentially (hooks append), rules/skills/agents/commands accumulate additively, CLAUDE.md files are concatenated into one file with --- separators. Query: agentihooks --query shows chain: [coding, colt].

agentihooks claude

Reads the claude: section from the active profile's profile.yml and maps fields to CLI flags:

profile.yml field CLI flag
permission_mode: bypassPermissions --dangerously-skip-permissions
model: sonnet --model sonnet
effort: high --effort high
worktree: true --worktree

Also loads env vars from ~/.agentihooks/.env and companion *.env files before exec. Extra arguments are passed through: agentihooks claude --verbose.

Bundles

A bundle is an external directory containing custom profiles and shared assets. Link it once; everything is auto-discovered.

my-bundle/
|-- .claude/                     # global assets shared by all profiles
|   |-- skills/
|   |-- agents/
|   |-- commands/
|   |-- rules/
|   +-- .mcp.json                # bundle-wide MCP servers
+-- profiles/
    +-- infra-ops/               # custom profile
        |-- CLAUDE.md
        |-- profile.yml
        +-- .claude/
            +-- settings.overrides.json
agentihooks init --bundle ~/dev/my-bundle    # link bundle + install
agentihooks --list-profiles                  # shows built-in + bundle profiles
agentihooks init --profile infra-ops         # use a bundle profile

Entity Merge Behavior

AgentiHooks entities (rules, skills, agents, commands, settings, MCP servers, CLAUDE.md) are installed through a 3-layer merge: agentihooks built-in -> bundle global -> profile-specific. Each entity type has different merge semantics:

Entity Merge type Same-name collision Notes
Rules (rules/*.md) Additive Later layer overwrites symlink All layers' unique files coexist in ~/.claude/rules/
Skills (skills/) Additive Later layer overwrites symlink Directory-based; same directory name = override
Agents (agents/*.md) Additive Later layer overwrites symlink Same filename = profile version wins
Commands (commands/*.md) Additive Later layer overwrites symlink Same filename = profile version wins
Settings (settings.json) Deep merge Dicts merge, hook arrays append, other arrays replace See key-by-key table below
MCP servers (.mcp.json) Additive Same server name = later layer overwrites Different server names accumulate
CLAUDE.md Copy (single) / Concatenate (chain) Last profile wins (single); all profiles merged (chain) Written as a real file, not a symlink (WSL/Windows compatible)
.env files Load order Later file overrides same key ~/.agentihooks/.env first, then *.env alphabetically

Key implication for rules: If your bundle defines rules/python-files.md and your profile also defines rules/python-files.md, the profile version wins (Layer 3 re-links over Layer 2). To add rules without overriding, use unique filenames. All rules from all layers with distinct names coexist in ~/.claude/rules/.

Settings.json key-by-key merge reference

settings.base.json is the source of truth. Running agentihooks init or the sync daemon deep-merges profile/bundle settings.overrides.json on top. The merge behavior depends on the type of each key:

Key Type Merge behavior Safe to override?
autoUpdatesChannel string Replaced Yes
skipDangerousModePermissionPrompt bool Replaced Yes
model string Replaced Yes — common profile override
env dict Key-by-key merge — new keys added, existing keys overwritten, unmentioned keys kept Yes — add or override env vars freely
permissions dict Key-by-key merge at dict level Partially
permissions.allow array Replaced entirely — profile's array is the full list Yes — define the complete permissions you want
statusLine dict Key-by-key merge Not recommended
hooks dict Key-by-key merge at the dict level Yes
hooks.PreToolUse (etc.) array Appended — profile hooks added after base hooks Yes — only define your extra hooks, base hooks are preserved

The rule: Dicts merge (keys combine). Hook arrays append (profile hooks are added after base hooks). All other arrays replace (profile's list wins). Profiles only need to define what's unique to them — base hooks are always preserved.

Hook Events

10 lifecycle events, all handled by python -m hooks:

Event What happens
SessionStart Injects session awareness, MCP hygiene reminder, MCP surface area warning
PreToolUse Secret scan (blocks on detection), file read deduplication, CLAUDE.md sanity check, tool error memory
PostToolUse Truncates verbose bash output, marks files read, records tool errors
Stop Scans transcript for errors, parses metrics, auto-saves memory
SessionEnd Logs transcript, clears file read cache, clears context refresh state
SubagentStop Logs subagent transcript
UserPromptSubmit Warns on detected secrets, context refresh (rules re-injection every N turns)
Notification Logs notifications
PreCompact Logs before context compaction
PermissionRequest Logs permission requests

StatusLine is not a hook event -- it is a native Claude Code setting handled by hooks/statusline.py. Emits a 2-3 line terminal status bar with context fill %, burn rate, cost, cache ratio, git branch, and quota.

Multi-Account Quota

The quota watcher is a headless Playwright daemon that scrapes claude.ai/settings/usage and writes JSON for the statusline. Supports multiple accounts.

# One-time: install Playwright's browser
~/.agentihooks/.venv/bin/python -m playwright install chromium

# Add accounts
agentihooks quota auth personal     # opens browser, prompts for sessionKey
agentihooks quota auth team         # add another account

# Manage
agentihooks quota list              # show all, mark active
agentihooks quota switch team       # switch + restart daemon
agentihooks quota remove personal   # delete account

Accounts are stored in ~/.agentihooks/quota-accounts/<name>.json. Enable in ~/.agentihooks/.env:

CLAUDE_USAGE_FILE=~/.agentihooks/claude_usage.json

Statusline output example:

session:53% [1h] | all:35% resets fri 10:00 am | sonnet:5% resets mon 12:00 am

Sync Daemon

scripts/sync_daemon.py watches 27+ source files across all 3 layers (built-in, bundle, profile) and auto-propagates changes to every registered target within one poll cycle. Additive only -- never deletes user files.

agentihooks daemon start            # start (60s default poll)
agentihooks daemon status           # show targets + watched files
agentihooks daemon stop             # kill daemon
Source change Affected targets
settings.base.json Global + ALL projects
profiles/{X}/* Targets using profile X
.env files Global + ALL projects
Bundle directory Global + ALL projects

An advisory file lock (~/.agentihooks/sync.lock) prevents concurrent writes between the daemon and manual agentihooks init commands.

Status & Diagnostics

agentihooks status validates your entire installation and shows the real state of your MCP fleet:

[OK] Profile: colt (bundle: ~/dev/agentihooks-bundle)
[OK] Hooks: 10/10 wired in settings.json
[OK] Python: uv/tools/agentihooks/bin/python3 (Python 3.11.15)
[OK] Daemons: sync (PID 1234), quota (PID 5678)
[OK] Redis: connected — 3568 keys (memory: 3540, file_cache: 14)
[OK] OTEL: enabled
[OK] Cost guardrails: 7/7 active
     + bash_filter: Truncates verbose bash output
     + file_dedup: Blocks re-reading unchanged files
     + context_audit: Tracks per-tool token consumption
     + effort_policy: Thinking/effort guidance, expensive subagent warnings
     + peak_hours: Peak billing indicator on statusline
     + compact_suggest: Smart /compact suggestions from audit data
     + claude_md_sanity: Blocks CLAUDE.md edits exceeding 200 lines
[OK] MCP: 9 servers (all disabled here) — 450 tools total, 0 active here
     - hooks-utils [stdio] (25 tools)
     - gateway-core [http] (93 tools)
     - gateway-infra [http] (131 tools)
     ...

The MCP check reads ~/.claude.json for server configs, resolves ${ENV_VAR} auth from your shell environment, queries each HTTP server via MCP protocol (initialize + tools/list) for real tool counts, and caches results for 1 hour at ~/.agentihooks/mcp-tool-cache.json. Per-project blacklists are read from ~/.claude.json projects block.

In-session skill: Use /agentihooks inside Claude Code to see the same diagnostics plus live session metrics (context fill, burn rate, per-tool consumption from the context audit).

MCP Tool Categories

Tools exposed by the hooks-utils MCP server, selectively loaded via MCP_CATEGORIES:

Category Tools Description
aws 3 Profile listing, account discovery
email 1 SMTP send with text / HTML / markdown
messaging 2 SQS + webhook with state enrichment
storage 1 S3 upload
database 2 DynamoDB put, PostgreSQL execute
compute 1 Lambda invocation (sync/async)
observability 2 Session log diagnostics, container log tailing
utilities 3 Markdown writer, env vars, tool listing

Configuration

All configuration goes in .env files in ~/.agentihooks/. Key variables:

Variable Default Description
AGENTIHOOKS_HOME ~/.agentihooks Root for logs, memory, and state
MCP_CATEGORIES all Comma-separated tool categories to load
TOKEN_CONTROL_ENABLED true Master switch for the token control layer
TOKEN_WARN_PCT 60 Context fill % that triggers a warning
TOKEN_CRITICAL_PCT 80 Context fill % that triggers a critical banner
BASH_FILTER_ENABLED true Truncate verbose bash output
FILE_READ_CACHE_ENABLED true Block redundant file re-reads
CONTEXT_AUDIT_ENABLED true Track per-tool token consumption across sessions
EFFORT_POLICY_ENABLED true Inject thinking/effort guidance at session start
DEFAULT_EFFORT medium Default reasoning effort (low/medium/high)
PEAK_HOURS_ENABLED true Show peak/off-peak billing indicator
COMPACT_SUGGEST_ENABLED true Smart /compact suggestions using audit data
AGENTIHOOKS_CLAUDE_MD_SANITY_CHECK true Block edits that would bloat CLAUDE.md past line limit
AGENTIHOOKS_CLAUDE_MD_MAXLINES 200 Max allowed lines in CLAUDE.md / CLAUDE.local.md
CONTEXT_REFRESH_ENABLED true Re-inject rules every N turns for attention decay mitigation
CONTEXT_REFRESH_INTERVAL 20 Re-inject every N user messages
REDIS_URL -- Redis connection string (graceful degradation when unavailable)
CLAUDE_USAGE_FILE -- Path to quota JSON (enables statusline quota display)
CLAUDE_USAGE_POLL_SEC 60 Quota watcher poll interval
AGENTIHOOKS_SYNC_POLL_SEC 60 Sync daemon poll interval
ENABLE_TOOL_SEARCH true Lazy-load MCP tools on demand

Complete table: Configuration Reference

Portability

Everything user-specific lives in ~/.agentihooks/:

~/.agentihooks/
|-- .venv/                     # canonical Python venv
|-- .env                       # main env vars (loaded first)
|-- *.env                      # companion env files (auto-sourced)
|-- state.json                 # install state, targets, active profile
|-- logs/                      # hook + daemon logs
|-- memory/                    # cross-session agent memory
|-- quota-accounts/            # multi-account auth state
|   +-- <name>.json
|-- claude_usage.json          # written by quota daemon, read by statusline
|-- sync-daemon.pid            # sync daemon PID
|-- sync-hashes.json           # daemon file hashes
|-- sync.lock                  # advisory lock
+-- mcp-tool-cache.json        # cached MCP tool counts (1h TTL, auto-refreshed)

To move to a new machine: clone the repo, copy ~/.agentihooks/.env, recreate the venv, run the installer:

uv venv ~/.agentihooks/.venv
uv pip install --python ~/.agentihooks/.venv/bin/python -e ".[all]"
agentihooks init

Per-Repo Config

agentihooks init --repo /path/to/repo    # per-repo config with profile picker

This writes .claude/settings.local.json in the target repo -- the highest-priority settings file in Claude Code. It merges the profile's permissions and MCP overrides into the repo scope.

Extending

Add a new MCP tool category with a register(server) function + one line in _registry.py. Add a new hook handler with one function + one entry in the dispatcher dict.

Guide: Extending AgentiHooks

Related Projects

Project Description
agenticore Claude Code runner and orchestrator
agentibridge MCP server for session persistence and remote control

License

See LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agentihooks-1.5.1.tar.gz (204.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentihooks-1.5.1-py3-none-any.whl (208.7 kB view details)

Uploaded Python 3

File details

Details for the file agentihooks-1.5.1.tar.gz.

File metadata

  • Download URL: agentihooks-1.5.1.tar.gz
  • Upload date:
  • Size: 204.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for agentihooks-1.5.1.tar.gz
Algorithm Hash digest
SHA256 6102c022b5e567195abf9e6850e7dadbbfe294984534ee54d52de5d166ed14ac
MD5 59efbc97d7b7646f0aff23096fa89922
BLAKE2b-256 5d8a291e516d8487ab78976755cdfaa59712cae7cc5091d8dc8ef357dd10b6ff

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentihooks-1.5.1.tar.gz:

Publisher: publish-pypi.yml on The-Cloud-Clock-Work/agentihooks

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file agentihooks-1.5.1-py3-none-any.whl.

File metadata

  • Download URL: agentihooks-1.5.1-py3-none-any.whl
  • Upload date:
  • Size: 208.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for agentihooks-1.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7a8a792c43ce94861e4913c15cfd841ced1914e1bf8083d5b24815e2ab43cde2
MD5 7b4fbd40d7b13d53bbabac18fb474e9d
BLAKE2b-256 23f7cbc7bba5d7ed04d1cd743a87abaeb9cbd29cc1d8b0466dd4abfcc2314cf1

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentihooks-1.5.1-py3-none-any.whl:

Publisher: publish-pypi.yml on The-Cloud-Clock-Work/agentihooks

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page