Testing
Input
Inline test input descriptor modeling an event payload.
Usage
Input(
*,
command=None,
file=None,
content=None,
old=None,
tool=None,
tool_input=None,
prompt=None,
script=None,
agent_type=None,
agent_id=None,
model=None,
output=None,
error=None,
reason=None,
source=None,
permission_mode=None,
cwd=None,
skip_permissions=None,
offset=None,
limit=None,
transcript=None,
tasks=None,
llm=None
)Set the fields the target event reads; all default to None.
Parameters
command: str | None = None-
Bash command for
PreToolUse/PostToolUse. file: str | FileFixture | None = None-
The tool’s file path. A FileFixture materializes a real temp file so size/stat-based guards run; a
strstays a virtual path. content: str | None = None-
New file content for Edit/
Write. old: str | None = Nonetool: str | None = None-
Tool name when no condition pins it.
tool_input: dict[str, Any] | None = None-
Verbatim raw tool-input mapping — an escape hatch that wins over the input synthesized from the other fields.
prompt: str | None = None-
An Agent/Task call’s prompt, or
UserPromptSubmittext. script: str | None = None-
A Workflow tool’s script source (synthesizes a Workflow call).
agent_type: str | None = None-
Subagent type for subagent events (an Agent/Task call’s
subagent_type). agent_id: str | None = None-
Subagent/teammate id — a non-empty value makes
evt.is_subagenttrue (and fills subagent events’ agent_id); each id also gets its ownmax_firesbudget. model: str | None = None-
Model for an Agent/Task call’s
modelinput field. output: str | None = None-
The tool result surfaced to
PostToolUseasevt.tool_response. error: str | None = None-
The failure text surfaced to
PostToolUseFailureasevt.error. reason: str | None = None-
SessionEndreason. source: str | None = None-
SessionStartsource (startup/resume/clear/compact). permission_mode: str | None = None-
Permission mode, e.g.
"plan"for plan-mode gating. cwd: str | None = None-
The session working directory surfaced as
evt.cwd, for hooks that resolve relative tool paths. skip_permissions: bool | None = None-
Pre-seeds
evt.skip_permissions(normally the process-tree walk for--dangerously-skip-permissions);Noneleaves the real walk in place. offset: int | None = None-
Readcall offset. limit: int | None = None-
Readcall limit. transcript: Path | TranscriptFixture | list[dict[str, Any]] | None = None-
Session history for transcript conditions — a path, a TranscriptFixture, or a raw list of transcript-line dicts.
tasks: list[dict[str, Any]] | None = None-
The native task list read via
evt.tasks. llm: dict[str, Any] | None = None-
Per-test LLM stub overrides merged over the default stub verdict (
fire/block/action/reasoning), e.g.llm={"fire": False}to exercise an LLM hook’s judge-declines path.
T
Namespaced transcript-fixture builders for Input(transcript=[...]) in inline tests.
Usage
T()Every builder returns a plain dict — a bare transcript line or a content block — that ~captain_hook.testing.types.TranscriptFixture accepts as-is, so T.* builders and hand-written raw dicts mix freely in one transcript list. Line builders (user(), assistant()) emit the envelope-free shape the fixture loader completes; block builders delegate to cc_transcript.synthetic so the shapes cannot drift from the parser.
Example
>>> from captain_hook.testing.types import Input
>>> Input(transcript=[
... T.user("Re-enter plan mode, don't do any more work."),
... T.assistant(T.tool("EnterPlanMode")),
... *T.tool_turn("Bash", result="ModuleNotFoundError", is_error=True, command="uv run pytest"),
... ])Input(transcript=…)
Methods
| Name | Description |
|---|---|
| assistant() |
An assistant transcript line whose message carries content.
|
| result() |
A tool_result content block; of correlates it to the call it answers.
|
| thinking() | A thinking content block for assistant(). |
| tool() |
A tool_use content block invoking name; keyword arguments become its input.
|
| tool_turn() | A paired assistant tool-call line and user tool-result line with matched ids. |
| user() |
A user transcript line whose message carries content.
|
assistant()
An assistant transcript line whose message carries content.
Usage
assistant(*content, **meta)Parameters
content: str | dict[str, Any] = ()-
Text strings (wrapped as
textblocks) or raw content-block dicts, typically a tool() call block. meta: Any = {}- Envelope fields merged onto the line.
Example
>>> T.assistant("planning the change"){‘type’: ‘assistant’, ‘message’: {‘content’: [{‘type’: ‘text’, ‘text’: ‘planning the change’}]}}
result()
A tool_result content block; of correlates it to the call it answers.
Usage
result(content="ok", *, of=None, is_error=False)Parameters
content: str = "ok"-
The result text surfaced to the tool caller.
of: dict[str, Any] | str | None = None-
The call this result answers — a tool() block (its id is read), a raw
tool_useid string, orNoneto mint a fresh unpaired id. is_error: bool = False- Marks a failed call, lifting to a failure in the parsed session.
Example
>>> call = T.tool("Bash", command="uv run pytest")
>>> T.result("ModuleNotFoundError", of=call, is_error=True){‘type’: ‘tool_result’, ‘tool_use_id’: …, ‘content’: ‘ModuleNotFoundError’, ‘is_error’: True}
thinking()
A thinking content block for assistant().
Usage
thinking(text)Example
>>> T.assistant(T.thinking("The user asked for a rename only.")){‘type’: ‘assistant’, ‘message’: {‘content’: [{‘type’: ‘thinking’, ‘thinking’: …}]}}
tool()
A tool_use content block invoking name; keyword arguments become its input.
Usage
tool(name, /, *, id=None, **input)Parameters
name: str-
The tool name, e.g.
"Bash"or"EnterPlanMode". id: str | None = None-
The
tool_useid; a freshtu-Nid is minted when omitted. Keep explicit ids outside thetu-<int>namespace auto-minting uses. input: Any = {}-
The tool input fields, e.g.
command="uv run pytest".
Example
>>> T.tool("Bash", command="uv run pytest"){‘type’: ‘tool_use’, ‘id’: …, ‘name’: ‘Bash’, ‘input’: {‘command’: ‘uv run pytest’}}
tool_turn()
A paired assistant tool-call line and user tool-result line with matched ids.
Usage
tool_turn(name, /, *, result="ok", is_error=False, **input)Splat the returned pair into a transcript list to model one full tool round-trip.
Parameters
name: str-
The tool name, e.g.
"Bash". result: str = "ok"-
The tool-result content joined back to the call.
is_error: bool = False-
Marks the call as failed.
input: Any = {}-
The tool input fields, e.g.
command="uv run pytest".
Example
>>> T.tool_turn("Bash", result="ModuleNotFoundError", is_error=True, command="uv run pytest")[{‘type’: ‘assistant’, …}, {‘type’: ‘user’, …}]
user()
A user transcript line whose message carries content.
Usage
user(*content, **meta)Parameters
content: str | dict[str, Any] = ()-
Text strings (wrapped as
textblocks) or raw content-block dicts. meta: Any = {}-
Envelope fields merged onto the line, e.g.
isMeta=Truefor a meta turn.
Example
>>> T.user("ship it"){‘type’: ‘user’, ‘message’: {‘content’: [{‘type’: ‘text’, ‘text’: ‘ship it’}]}}
Allow
Inline test expectation: the hook should allow (return None or action "allow").
Usage
Allow(*, explicit=False)explicit=True requires an actual allow result — None no longer matches, so e.g. a PermissionRequest hook must have answered the dialog itself.
Parameter Attributes
explicit: bool = False
Block
Inline test expectation: the hook should block. Optional regex pattern matches the block message.
Usage
Block(*, pattern=None)Parameter Attributes
pattern: str | None = None
Warn
Inline test expectation: the hook should warn. Optional regex pattern matches the warning message.
Usage
Warn(*, pattern=None)Parameter Attributes
pattern: str | None = None
Rewrite
Inline test expectation: the hook should rewrite the tool input.
Usage
Rewrite(pattern=None, **fields)pattern is a substring matched against the rewritten command (updated_input["command"]) — substring, not regex, so an absolute path prefix in the rewritten command does not break the match. Additional keyword arguments substring-match against the named updated_input field, so an Agent auto-upgrade can assert Rewrite(model="sonnet"); all given fields (and pattern) must match.
Parameter Attributes
pattern: str | None = Nonefields: str = {}
Ask
Inline test expectation: the hook returned no result (None).
Usage
Ask()FileFixture
Inline-test file descriptor: materialized to a real temp file so size/stat-based guards run for real.
Usage
FileFixture(*, size=None, content=None, name=None, home=False)home=True materializes the file under a per-test temporary “home” directory instead of the shared fixture directory, and run_inline_tests swaps $HOME to that directory for the duration of that one test’s hook execution — restored afterward even on failure — so an os.path.expanduser-based hook resolves deterministically. Requires name.
Parameter Attributes
size: int | None = Nonecontent: str | None = Nonename: str | None = Nonehome: bool = False
TranscriptFixture
A lightweight transcript stub for use in inline tests.
Usage
TranscriptFixture(messages)Wraps a list of raw transcript-line dicts that get lifted into a query Session when the test runs; missing envelope fields are synthesized.