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
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
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 fromToolCallBase.name, the tool name). args: Any-
The value exposed to the script as its
argsglobal. 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 NoneTrue
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