Example: a Python tool
mytool.py refuses destructive shell commands. mytool.harness.toml
declares its instructions, a skill and two bridged hooks; agent-harness-adapter installs
them and runs the hooks.
agent-harness-adapter install --manifest examples/python-tool/mytool.harness.toml --harness claude,codex,gemini
test_example.py installs it into a temporary project and runs each
installed hook command the way Claude Code, Codex and Gemini CLI would, with
their own input. CI runs it:
cargo build -p agent-harness-adapter
python3 examples/python-tool/test_example.py target/debug/agent-harness-adapter
The manifest
Section titled “The manifest”# A tool written in Python, plugged into agent harnesses by `agent-harness-adapter`.version = 1name = "mytool"instructions = { file = "agent/instructions.md" }
[[skills]]name = "mytool"description = "Check a shell command with mytool before running it."body = { file = "agent/skill.md" }
# Bridged hooks: `agent-harness-adapter hook` gives mytool.py Claude Code's hook input in every harness.[[hooks]]event = "session-start"run = "python3 mytool.py hook"
[[hooks]]event = "pre-tool"tools = "shell"run = "python3 mytool.py hook"The tool
Section titled “The tool”"""mytool: an example tool in Python, plugged into agent harnesses by `agent-harness-adapter`.
`python3 mytool.py hook` is a hook in Claude Code's format: it reads ClaudeCode's hook input on stdin and answers as Claude Code reads an answer (exit 2with the reason on stderr blocks; plain stdout at session start is context).`agent-harness-adapter hook` translates both for whichever harness ran it."""
import jsonimport sys
REFUSED = ("rm -rf /", "git push --force")
def hook(event): """Answer one hook input: (exit code, stdout, stderr).""" name = event.get("hook_event_name") if name == "SessionStart": return 0, "mytool is watching shell commands.", "" if name == "PreToolUse" and event.get("tool_name") == "Bash": command = (event.get("tool_input") or {}).get("command", "") for refused in REFUSED: if refused in command: return 2, "", f"mytool refuses `{refused}`" return 0, "", ""
def main(): if sys.argv[1:] == ["hook"]: code, out, err = hook(json.load(sys.stdin)) print(out, end="") print(err, end="", file=sys.stderr) sys.exit(code) elif sys.argv[1:2] == ["check"]: refused = [r for r in REFUSED if r in " ".join(sys.argv[2:])] print("refused" if refused else "allowed") else: sys.exit("usage: mytool.py hook | check <command>")
if __name__ == "__main__": main()