A fake claude / codex CLI. Deterministic output. No model, no network, no tokens. Iterate locally; run in CI without an API key.
Local hook development. A Type="http" or Type="command" hook fires the same JSON payload real Claude Code fires. Wire it to your handler, script a /fake-tool + /fake-tool-result sequence, watch the payload land. Sub-second iterations.
Deterministic CI. Drop testagent in wherever your pipeline shells out to claude or codex. Argv-compatible, --print --output-format stream-json emits the same frame shapes a real run would. No API key in the CI secret store, no rate-limit flakes, same bytes every run.
go install github.com/paultyng/testagent@latestPin testagent alongside your other dependencies so CI uses the same version without a separate install step:
go get -tool github.com/paultyng/testagent@latest
go tool testagent claude --helpDeclare a Type="command" hook in settings.json. It pipes the event JSON to a shell command's stdin — here, a one-liner that captures the payload to disk:
{"hooks":{"PostToolUse":[{"hooks":[{"type":"command","command":"jq . > tool-use.json"}]}]}}Run testagent with a scripted tool-use cycle:
testagent claude --settings settings.json <<'EOF'
/fake-tool read_file {"path":"main.go"}
/fake-tool-result {"content":"package main"}
/exit
EOFInspect what your hook handler received:
jq . tool-use.json
# {
# "hook_event_name": "PostToolUse",
# "session_id": "...",
# "tool_name": "read_file",
# "tool_input": {"path": "main.go"},
# "tool_response": {"content": "package main"},
# ...
# }Same shape Claude Code fires. Sub-second feedback. No model, no network, no API key.
See COMPATIBILITY.md for the per-vendor matrix of flags, slash commands, hook events, hook handler types, and REPL behaviors.
- No model. Output is scripted: prompt echoes,
/fake-toolblocks you supply, fixed stream-json frames. testagent doesn't generate text. - Not every Claude hook event yet. Currently fires
SessionStart,SessionEnd,UserPromptSubmit,PreToolUse,PostToolUse,Stop,PreCompact,PostCompact.NotificationandSubagentStoparen't modeled. - Not every Claude hook handler type.
Type="http"andType="command"ship.Type="agent"requires a model and is out of scope. - No MCP server fake. testagent is an MCP client — it connects to a real server and dispatches
tools/call. It doesn't fake the server side.
MIT.

