Skip to main content

harness-hooks

Installs the hooks and settings that config files list into Claude Code and Codex, and removes them. Works on macOS and Linux.

Run it with uv:

uvx harness-hooks install path/to/config.json
uvx harness-hooks remove path/to/config.json

Or install it once, which puts harness-hooks on your PATH:

uv tool install harness-hooks

Config

A config is a JSON file with a name and any of these parts:

  • hooks: commands the agents run at their events.
  • env and settings: values for the agents' settings files.
  • inputs: questions that install asks, such as for a token.
  • files: files the hooks need.
  • agents, such as ["claude"]: limits the config to those agents.

Hooks

{
  "name": "notify",
  "files": ["notify.py"],
  "hooks": {
    "Stop": [{"command": "python3 {dir}/notify.py {agent}", "timeout": 5}],
    "claude": {
      "Notification": [{"matcher": "idle_prompt", "command": "python3 {dir}/notify.py claude"}]
    },
    "codex": {
      "PreToolUse": [{"matcher": "^request_user_input", "command": "python3 {dir}/notify.py codex"}]
    }
  }
}
  • Events in hooks go to both agents; events in hooks.claude and hooks.codex only to that agent.
  • {dir} becomes the folder with the hooks' files, so hooks can call scripts there. {agent} becomes claude or codex.
  • matcher and command mean what they mean in each agent's own hook files. Other fields, such as timeout, are copied as they are.
  • files, if given, lists the files the hooks need, as paths inside the config's folder.

Settings

A config can set agent settings and ask for personal values, such as keys:

{
  "name": "tracing",
  "inputs": {
    "key": {"ask": "Tracing key", "secret": true},
    "token": {"ask": "Gateway token", "secret": true, "file": true}
  },
  "env": {"TRACE_HOST": "https://trace.example.com", "TRACE_KEY": "{key}"},
  "settings": {
    "claude": {"apiKeyHelper": "cat {token}"},
    "codex": {"model_providers": {"gateway": {"auth": {"command": "cat", "args": ["{token}"]}}}}
  }
}
  • env sets environment variables for each selected agent.
  • settings.claude holds keys of Claude's settings.json, settings.codex keys of Codex's config.toml.
  • inputs are questions that install asks; {key} in env and settings becomes the answer. Secret answers don't show as you type.
  • With "file": true, the answer goes to a file only you can read, and {token} becomes its path. The secret stays out of the settings files.

install asks only for values it hasn't written yet; --ask asks again, for example after a token change. Without a terminal, set HARNESS_HOOKS_<INPUT>, such as HARNESS_HOOKS_TOKEN.

One command can take several configs, and asks each question once:

uvx harness-hooks install gateway.json langfuse.json otel.json

examples/team-setup is a full setup: an LLM gateway or a subscription, Langfuse traces and metrics.

Your own values stay

harness-hooks changes or removes only the values it set and nobody edited since. It never overwrites a value you set yourself, and tells you when one differs from the config.

install drops the values a config no longer lists, with the same care. A value that two configs set stays until both are removed.

Settings go only to your own files: --project refuses a config with env, settings or inputs.

Copies

With files in the config, install copies those files, so the hooks keep working when the config's folder moves or is deleted. Run install again to bring in changed files; remove deletes the copies.

Without files, or with --editable, {dir} is the config's folder, so an edit takes effect at once. --editable also deletes copies left by an earlier install. --project never copies.

Where hooks go

By default into ~/.claude/settings.json and ~/.codex/hooks.json, so they run in every project. CLAUDE_CONFIG_DIR and CODEX_HOME move these files, as they do for the agents.

With --project, into .claude/settings.json and .codex/hooks.json of the git repository that holds the config. Commit them, and everyone who clones the repository gets the hooks. {dir} is then found from the repository root, so the hooks work in any clone. Claude reads them only in sessions started at the repository root. Codex reads them only after you trust the project.

--agent claude or --agent codex touches only that agent.

Updating and removing

Keep name unchanged when updating or removing a config; it can't hold /. install replaces that config's hooks, so a hook dropped from the config disappears; hooks you added yourself stay.

Codex asks you to review new or changed hooks at its next start. It remembers approvals by a hook's place in the file, so removing hooks can make it ask again about the hooks after them.

Development

From a clone, uv tool install --editable . runs the code in the clone, so an edit takes effect at once.

uv run --no-project --with tomlkit python -m unittest

Metadata

Release files for harness-hooks 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for harness-hooks 0.2.0
File Size Uploaded
harness_hooks-0.2.0.tar.gz 13.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for harness-hooks 0.2.0
File Interpreter ABI Platform
harness_hooks-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 23.2 kB

Release files / harness_hooks-0.2.0.tar.gz

Download URL harness_hooks-0.2.0.tar.gz
Size 13.6 kB
Tags Source
SHA-256 checksum
How to use checksums
383722f3e105fc69e337ef52b937fb9ad66bc1fcae2ae587af1a850fa97e4573
BLAKE2b-256 checksum
How to use checksums
2431bf1e21857310be2d6e1334bce76e80a0ea12fdec4ff2b3e5611100953bf9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / harness_hooks-0.2.0-py3-none-any.whl

Download URL harness_hooks-0.2.0-py3-none-any.whl
Size 9.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d036fd14125e8b70d272729b501500b1f68d4a096fbe71cb5fea52d575e1d536
BLAKE2b-256 checksum
How to use checksums
ae3d5f927b8d967425c97bc8fec318c37c59af65a231ac461ecd74d1fe34c8f7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page