Tool calls

ToolCall

ToolCall=(
    BashCall
    | EditCall
    | MultiEditCall
    | WriteCall
    | ReadCall
    | NotebookEditCall
    | GrepCall
    | GlobCall
    | TaskCall
    | WorkflowCall
    | SkillCall
    | TaskCreateCall
    | TaskUpdateCall
    | ExitPlanModeCall
    | CodeModeCall
    | ApplyPatchCall
    | UpdatePlanCall
    | WriteStdinCall
    | SpanEditCall
    | OtherCall
)

ToolCallBase

Common shape of every typed tool call.

Usage

ToolCallBase()

Attributes

name: builtins.str

The tool name exactly as invoked (aliases are not normalized — the digest must match what the hook saw).

raw: collections.abc.Mapping[str, Any] | str | None
The verbatim input value — a mapping for structured calls, a plain string for Codex calls, or None when absent. The only digest substrate.

Attributes

Name Description
digest The cross-language content digest of this call.
digest

The cross-language content digest of this call.

digest: ids.ToolDigest

parse_tool_call()

Parse a tool’s name and raw input into the typed hierarchy.

Usage

Source

parse_tool_call(name, input, *, on_error="raise")

Strict by default: a known tool whose input is malformed raises ToolInputError (leniency lives in tests). Malformed covers a required field that is missing, explicitly null, or of the wrong runtime type — validation happens here at the boundary, never downstream of a typed field. The wild-data boundaries — the hook runtime and the activity lift — pass on_error='other' so a Claude Code shape change or a model-emitted invalid call degrades to OtherCall — with a still-correct digest, since the raw input is the substrate — instead of crashing every hook fire or session lift. A non-mapping input raises under strict mode; under on_error='other' it degrades to an OtherCall over the original input verbatim, so its digest reflects that input rather than an empty mapping. On a degraded OtherCall, error is None when the strict pass found no malformation — an untyped tool over a well-formed mapping, or a codex-style verbatim string — and otherwise carries the strict failure message (a missing, null, or wrong-typed field, or a non-mapping input to a built-in tool). Under strict mode, an unknown tool name with a string input remains an OtherCall with error=None because unknown names are the tolerance zone for untyped Codex tools.

v14 contract: input is decoded-JSON values. It is serialized to a JSON document for the native parser, so tuples normalize to lists and non-string keys to strings (JSON semantics). Values JSON cannot express — a datetime, bytes, a reference cycle — are out of contract: strict mode raises, and on_error='other' degrades to a FallbackCall holding the original mapping verbatim rather than crashing.

Example

>>> call = parse_tool_call("Edit", {"file_path": "a.py", "old_string": "x", "new_string": "y"})
>>> call.new

‘y’

ToolInputError

A known tool’s input did not match its expected shape.

Usage

Source

ToolInputError()

BashCall

A Bash/Execute shell invocation.

Usage

BashCall()

Attributes

Name Description
command_line The command parsed into a ~CommandLine.
command_line

The command parsed into a ~CommandLine.

command_line: CommandLine

ReadCall

A Read of a file, optionally windowed.

Usage

ReadCall()

WriteCall

A Write/Create of a whole file.

Usage

WriteCall()

EditCall

An Edit replacement of old with new in one file.

Usage

EditCall()

MultiEditCall

A MultiEdit applying edits to one file, in order.

Usage

MultiEditCall()

NotebookEditCall

A NotebookEdit replacing a cell’s source.

Usage

NotebookEditCall()

GlobCall

A Glob file-pattern search.

Usage

GlobCall()

GrepCall

A Grep content search.

Usage

GrepCall()

ExitPlanModeCall

An ExitPlanMode/ExitSpecMode plan submission.

Usage

ExitPlanModeCall()

SkillCall

A Skill invocation.

Usage

SkillCall()

TaskCall

An Agent/Task subagent dispatch.

Usage

TaskCall()

TaskCreateCall

A TaskCreate tracker entry.

Usage

TaskCreateCall()

TaskUpdateCall

A TaskUpdate tracker change.

Usage

TaskUpdateCall()

WorkflowCall

A Workflow dynamic-orchestration dispatch.

Usage

WorkflowCall()

Attributes

script: str | None

The inline workflow script, when passed directly.

script_path: str | None

Path to a script file on disk, when passed instead of script.

workflow_name: str | None

A predefined workflow’s name (raw["name"] — distinct from ToolCallBase.name, the tool name).

args: Any

The value exposed to the script as its args global.

resume_from_run_id: str | None
A prior run to resume from.

OtherCall

A tool the platform does not type: unknown names, MCP tools, and — under

Usage

OtherCall()

on_error='other' — known tools whose input failed to parse.

Attributes

Name Description
error The strict-parse failure this call degraded from; None when the payload was well-formed but the tool has no typed model.
error

The strict-parse failure this call degraded from; None when the payload was well-formed but the tool has no typed model.

error: builtins.str | None

EditSpan

One replacement within a MultiEdit call, in application order.

Usage

EditSpan()

Hunk

A before/after content pair lowered from an edit-shaped tool call.

Usage

Hunk()

Attributes

old: builtins.str

The content replaced; empty for pure additions such as Write.

new: builtins.str
The content written.

hunks_of()

Lower an edit-shaped call to before/after hunks; () for the rest.

Usage

hunks_of(call)

MultiEdit yields one hunk per span in application order — never just the first. Write and NotebookEdit are pure additions with an empty old side. ~cc_transcript.tools.SpanEditCall yields none: its payload carries no pre-image, so no honest hunk can be derived.

file_path_of()

The file a call targets, when it targets one.

Usage

file_path_of(call)

mcp_parts()

Split an mcp__server__tool name into (server, tool), else None.

Usage

mcp_parts(name)

Example

>>> mcp_parts("mcp__semble__search")

(‘semble’, ‘search’)

>>> mcp_parts("Bash") is None

True

mcp_access()

Classify an MCP tool segment as "read" or "write" by its verbs.

Usage

mcp_access(tool)

Returns "read" when tool starts with, or has an underscore-delimited token equal to, a read verb (get, list, search, …); otherwise "write". The token check catches namespaced names like ccx_read.

Example

>>> mcp_access("search")

‘read’

>>> mcp_access("ccx_read")

‘read’

>>> mcp_access("deploy")

‘write’

TOOL_ALIASES

TOOL_ALIASES: dict[str, str] = {
    "Bash": "Execute",
    "Edit": "apply_patch",
    "Write": "Create",
    "Agent": "Task",
    "WebFetch": "FetchUrl",
    "ExitPlanMode": "ExitSpecMode",
}

expand_tool_names()

Expand a pipe-separated tool spec to include alias and MCP bare spellings.

Usage

expand_tool_names(spec)

matches_names()

Whether actual is one of names, exactly or as an MCP tool suffix.

Usage

matches_names(actual, names)

True when actual is in names, or when it splits as mcp__<server>__<tool> on the first two __ and <tool> — or the built-in gate its registered spec behaves_like — is in names. That closure lets a registered MCP tool (e.g. one that gates as Edit) match an Edit gate even under a name no built-in gate would catch. Display-name aliases from ~cc_transcript.tools.TOOL_ALIASES are not closed over — names is taken verbatim; pre-expand with expand_tool_names() for those.

Example

>>> matches_names("mcp__github__Grep", {"Grep"})

True

>>> matches_names("Execute", {"Bash"})

False

tool_name_matches()

Whether actual matches a pipe spec, honoring aliases and MCP suffixes.

Usage

tool_name_matches(actual, spec)

Example

>>> tool_name_matches("Execute", "Bash|Grep")

True

>>> tool_name_matches("mcp__github__Grep", "Grep")

True