Testing

Input

Inline test input descriptor modeling an event payload.

Usage

Source

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 str stays a virtual path.

content: str | None = None

New file content for Edit/Write.

old: str | None = None

Pre-edit content for Edit and diff_lint.

tool: 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 UserPromptSubmit text.

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_subagent true (and fills subagent events’ agent_id); each id also gets its own max_fires budget.

model: str | None = None

Model for an Agent/Task call’s model input field.

output: str | None = None

The tool result surfaced to PostToolUse as evt.tool_response.

error: str | None = None

The failure text surfaced to PostToolUseFailure as evt.error.

reason: str | None = None

SessionEnd reason.

source: str | None = None

SessionStart source (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); None leaves the real walk in place.

offset: int | None = None

Read call offset.

limit: int | None = None

Read call 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

Source

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

Source

assistant(*content, **meta)
Parameters
content: str | dict[str, Any] = ()

Text strings (wrapped as text blocks) 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

Source

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_use id string, or None to 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

Source

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

Source

tool(name, /, *, id=None, **input)
Parameters
name: str

The tool name, e.g. "Bash" or "EnterPlanMode".

id: str | None = None

The tool_use id; a fresh tu-N id is minted when omitted. Keep explicit ids outside the tu-<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

Source

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

Source

user(*content, **meta)
Parameters
content: str | dict[str, Any] = ()

Text strings (wrapped as text blocks) or raw content-block dicts.

meta: Any = {}
Envelope fields merged onto the line, e.g. isMeta=True for 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

Source

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

Source

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

Source

Warn(*, pattern=None)

Parameter Attributes

pattern: str | None = None

Rewrite

Inline test expectation: the hook should rewrite the tool input.

Usage

Source

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 = None
fields: str = {}

Ask

Inline test expectation: the hook returned no result (None).

Usage

Source

Ask()

For PermissionRequest hooks this means the permission dialog shows; a warn result fails Ask().

FileFixture

Inline-test file descriptor: materialized to a real temp file so size/stat-based guards run for real.

Usage

Source

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 = None
content: str | None = None
name: str | None = None
home: bool = False

TranscriptFixture

A lightweight transcript stub for use in inline tests.

Usage

Source

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.