Tools
Every tool the agent can call, with signatures and parameters. Cast built-ins, Claude Code SDK tools, peer-dialogue wire tags, and a per-extension index.
Tools come from three places: Cast injects the framework MCP tools below, the Claude Code SDK contributes a fixed set of general-purpose tools, and each active extension contributes its own. Peer dialogue uses wire tags instead of MCP tools — visually, MCP tools carry a coral left rule, wire tags carry amber.
Conversation memory
message_log__search(query, limit?, channel?, before?, after?, max_tokens?)
Search past messages by keyword. Returns previews with IDs — use message_log__read for full text.
Parameters
query[string]Full-text search query.- optional
limit[integer 1–50, default 20]Max results to return. - optional
channel[string]Filter to a specific channel. - optional
before[ISO timestamp]Only messages before this timestamp — pagination cursor. - optional
after[ISO timestamp]Only messages after this timestamp — time-range filter. - optional
max_tokens[integer 1–1000, default 200]Max tokens per preview snippet.
Returns
Messages (N[, has_more=true, next_cursor=ISO_TIMESTAMP]):
[ID] [ISO_TIMESTAMP] ROLE: PREVIEW
No messages found.
Caveats
Scoped to the current participant on this agent. A caller can only see messages addressed to themselves — never crosses identities.
message_log__recent(limit, max_tokens?, before?, after?)
Browse recent messages newest-first without a keyword. Same scope as message_log__search.
Parameters
limit[integer 1–50]Number of messages to return.- optional
max_tokens[integer 1–1000, default 200]Max tokens per preview snippet. - optional
before[ISO timestamp]Pagination cursor — only messages before this timestamp. - optional
after[ISO timestamp]Time-range filter — only messages after this timestamp.
Returns
Messages (N[, has_more=true, next_cursor=ISO_TIMESTAMP]):
[ID] [ISO_TIMESTAMP] ROLE: PREVIEW
No messages found.
message_log__read(id, max_tokens?)
Read the full text of a specific message by ID.
Parameters
id[integer]Message ID from a search or recent result.- optional
max_tokens[integer 1–10000, default 2000]Max tokens of body text to return.
Returns
[ID] [ISO_TIMESTAMP] ROLE (CHANNEL): FULL_TEXT
Message ID not found.
Access denied: message belongs to a different participant.
Caveats
Reads are denied if the message belongs to a different participant.
conversation__list_summaries(channel?)
List recent conversations across channels. Shows participant, status, last activity, and summary when available.
Parameters
- optional
channel[string]Filter to one channel.
Returns
- participant: ID, channel: NAME, status: STATUS, last_activity: DURATION[, summary: SUMMARY]
No recent conversations.
Caveats
May prepend a co-participant visibility note when the current channel hides them, and a privacy reminder when results include other participants' conversations.
conversation__write_summary(summary)
Submit a summary of the current conversation. Stored and visible via conversation__list_summaries.
Parameters
summary[string]Concise summary — decisions, action items, outcomes.
Returns
Summary saved.
Cannot submit summary: no conversation context.
Conversation lifecycle
conversation__end(cooldown_seconds?)
End the current conversation after a cooldown. Cleanup and summary run as usual. If the participant sends a message before the cooldown elapses, the end is cancelled and the agent is notified.
Parameters
- optional
cooldown_seconds[integer 60–86400, default 300]Seconds before the conversation expires. Clamped to the channel's idle_timeout.
Returns
Conversation will end in N seconds. If the participant sends a message, the end will be cancelled.
Caveats
Persistent channels only — single-shot conversations end automatically and have nothing to release.
Cross-conversation push
All pushes are fire-and-forget. If the receiver later rejects the push (ACL revoked, target in draft, etc.) the agent sees a <cast:rejection request="ID"> on a later turn — full details on Runtime › Wire format.
conversation__push_to_channel(channel, text, target_agent?)
Push a turn into another channel. Opens cold or continues an active conversation. Without target_agent the push stays on this agent; with target_agent it crosses to a peer.
Parameters
channel[string]Target channel name. For sharded channels, use "name~qualifier" to address a specific sub-conversation.text[string]Message content delivered to the target channel.- optional
target_agent[string]Peer agent alias (e.g. "knowledge"). Omit for a same-agent push.
Returns
Pushed to CHANNEL for PARTICIPANT. id: REQUEST_ID.
Pushed to CHANNEL for PARTICIPANT via ALIAS. id: REQUEST_ID.
Push failed: REASON
<cast:rejection request="ID">REASON</cast:rejection>
Caveats
Cross-agent pushes hand the originating user to a peer agent and land only if the receiving peer has granted that user access. Passing your own alias is equivalent to omitting.
conversation__push_to_participant(target_participant, channel, text)
Push a turn into a different participant's conversation on this agent. The target participant's runner sees it as a new turn.
Parameters
target_participant[string]Target participant address. Use agent__list_participants to enumerate.channel[string]Target channel for that participant. Sharded as "name~qualifier".text[string]Message content.
Returns
Pushed to CHANNEL for TARGET_PARTICIPANT. id: REQUEST_ID.
Push failed: REASON
<cast:rejection request="ID">REASON</cast:rejection>
Caveats
Intra-agent only, no target_agent option. The target must be a user who has access to the target channel, and the channel must let co-participants reach each other.
Peer dialogue
Peer-to-peer messaging uses wire tags rather than MCP tools — the agent writes them inline in its response and the framework routes them. Validation rules and full attribute schema on Runtime › Wire format.
<cast:query target="@PEER"> QUESTION </cast:query>
Ask a peer agent a question and wait for its answer. The body of the tag is the question; the answer arrives on a later turn as <cast:answer request="ID">.
Parameters
target[string]Peer alias prefixed with @.
Returns
<cast:answer request="ID">BODY</cast:answer>
<cast:pending request="ID">REASON</cast:pending>
<cast:rejection request="ID">REASON</cast:rejection>
Caveats
Gated by the peer's q ACL bit toward this agent.
<cast:request target="@PEER"> MESSAGE_BODY </cast:request>
Fire-and-forget message to a peer agent. No reply expected. Returns an id; if delivery is rejected later, a rejection tag carrying that id arrives.
Parameters
target[string]Peer alias prefixed with @.
Returns
(nothing inline)
<cast:rejection request="ID">REASON</cast:rejection>
Caveats
Gated by the peer's r ACL bit.
<cast:answer request="ID"> ANSWER_BODY </cast:answer>
Reply to an inbound peer query. The request id is the one carried on the inbound <cast:query>.
Parameters
request[string]The id from the inbound query.
Returns
(nothing inline)
Peer awareness
agent__list_peers()
List peer agents and your relationship with each — who you can query, who can message you, per-channel capability summary. Sharded channels render as name~* — substitute your own qualifier to address a sub-conversation.
Returns
- ALIAS (CANONICAL_ADDRESS)[: DESCRIPTION]
on CHANNEL|CHANNEL~*: CAPABILITIES
No peer agents configured.
agent__list_channels()
List the channels where this conversation's participant is placed — the rooms conversation__push_to_participant can land in. The agent itself and operator surfaces see every configured channel. Sharded channels render as name~*.
Returns
- CHANNEL[~*] — your access: BITS
No channels to list.
agent__list_participants(channel?)
List the members of a channel you are placed in, as identities in the exact form push_to_participant accepts, with day-level recency. Scoped by caller standing: a cell can list exactly what the push gate would let it reach, and a query outside its rooms is denied without revealing whether the channel exists. The agent itself and operator surfaces get unfiltered views — and the agent-wide registry when no channel is in play.
Parameters
- optional
channel[string]Optional. Accepts name~qualifier (qualifier ignored — shards share membership). Omitted: the current channel for members, the registry for the agent itself and operator surfaces.
Returns
Members of "CHANNEL":
- IDENTITY (last active: YYYY-MM-DD | no session yet)
- IDENTITY — peer agent (request counterparty, not a push target)
- IDENTITY (last active: ISO_TIMESTAMP)
You are not authorized on channel "CHANNEL".
Request tracking
request__list()
List open requests for the current channel and participant. Shows both inbound (queries you received) and outbound (queries you sent), with status and age.
Returns
## Outbound (queries you sent)
- [STATUS] REQUEST_ID → TARGET_AGENT (TARGET_CHANNEL) — AGE
## Inbound (queries you received)
- [STATUS] REQUEST_ID from FROM_AGENT — AGE
No requests found for this context.
request__close(request_id)
Close a request by ID. Closing an outbound request means 'I no longer need this answer.' Closing an inbound request means 'I am declining this' and sends a rejection back to the requester.
Parameters
request_id[string]The request ID to close.
Returns
Closed outbound request ID.
Closed inbound request ID and sent rejection.
Request ID not found or already closed.
Request ID belongs to a different context.
request__close_all()
Close all open requests for the current channel and participant. Sends rejections for every inbound request.
Returns
Closed N inbound + M outbound requests.
No open requests to close.
Scheduling
A task is an independent agent session that runs later — it spawns a full agent with all tools. Use tasks for things that need to happen at a future time or on a schedule, not for things you can do now.
task__schedule(prompt, schedule_type, schedule_value, timezone?)
Schedule a deferred or recurring task. Cron schedules use the agent's timezone by default. Bare ISO timestamps (no Z, no offset) are interpreted as agent-local.
Parameters
prompt[string]What the agent should do when the task runs. Include all necessary context — wrap output in <cast:internal> to suppress delivery.schedule_type['cron' | 'once']cron = recurring at specific times; once = run once at a specific time.schedule_value[string]cron: "0 10 * * *" (10am local). once: ISO-8601, e.g. "2026-02-01T15:30:00" (agent-local) or with offset "…-05:00".- optional
timezone[IANA timezone]Override agent's default timezone. Specify only when scheduling for a different tz.
Returns
Task scheduled (ID): SCHEDULE_TYPE - SCHEDULE_VALUE
Invalid cron: "VALUE". …
Invalid timestamp: "VALUE". …
Invalid timezone: "TIMEZONE". Use IANA format like "America/New_York" or "Europe/London".
task__list()
List scheduled tasks (active and paused). Completed and cancelled tasks are not shown.
Returns
Scheduled tasks:
- [ID] PROMPT_PREVIEW... (SCHEDULE_TYPE: SCHEDULE_VALUE) - STATUS, next: ISO_TIMESTAMP
No scheduled tasks.
task__pause(task_id)
Pause a scheduled task. It will not run until resumed.
Parameters
task_id[string]The task ID to pause.
Returns
Task ID paused.
Task ID not found.
Unauthorized: cannot pause this task.
task__resume(task_id)
Resume a paused task. The next_run is recomputed for cron tasks so stale schedules don't fire immediately.
Parameters
task_id[string]The task ID to resume.
Returns
Task ID resumed.
Task ID not found.
Unauthorized: cannot resume this task.
task__cancel(task_id)
Cancel and delete a scheduled task.
Parameters
task_id[string]The task ID to cancel.
Returns
Task ID cancelled.
Task ID not found.
Unauthorized: cannot cancel this task.
task__list_runs(limit?)
View recent task dispatch history. Shows when tasks fired and what they were.
Parameters
- optional
limit[integer 1–100, default 20]Number of recent runs to return.
Returns
Recent task runs:
- ISO_TIMESTAMP | PROMPT_PREVIEW
No task runs found.
Time
time__now(timezone?)
Get the current time as a human-readable string with day of week, date, time, and timezone. Defaults to the agent's timezone.
Parameters
- optional
timezone[IANA timezone]Override the default, e.g. "America/New_York", "Asia/Tokyo".
Returns
WEEKDAY ISO_TIMESTAMP_WITH_OFFSET
Invalid timezone: "TIMEZONE". …
Caveats
Use rather than guessing — the agent's wall clock isn't carried in the conversation context past the system-prompt assembly time.
time__convert(time, from_tz, to_tz)
Convert a time between timezones. Returns formatted times in both. Use for cross-timezone scheduling — never compute offsets yourself (DST and historical offsets aren't safe to derive).
Parameters
time[ISO 8601 string]Time to convert.from_tz[IANA timezone]Source timezone.to_tz[IANA timezone]Target timezone.
Returns
FROM_TZ: WEEKDAY ISO_WITH_OFFSET TO_TZ: WEEKDAY ISO_WITH_OFFSET
Invalid timezone: "TIMEZONE". …
Invalid time: "TIME". …
Filesystem watches
A feed is an ordered, append-only JSONL stream that peers can observe. The framework assigns a monotonic id starting at 1 so watchers can cursor through rows. Use feeds for coordination — meeting points between channels or agents, not as journals or audit logs.
file__append_feed(path, data, meta?)
Append a row to a feed at the given container path. Creates the file if missing; the parent directory must already exist on a writable mount.
Parameters
path[string]Container-side path, e.g. /memory/letter.jsonl.data[JSON value]Row content — any JSON-serializable value. Surfaced to humans/transports by convention.- optional
meta[JSON value]Coordination metadata — agents-only convention, not surfaced to humans.
Returns
Appended row id=N to PATH.
Feed corruption detected at row offset N: REASON. Refusing to append. Operator must repair.
Parent directory does not exist: HOST_PATH. …
No writable mount matches parent of PATH.
Parent directory is a symlink (rejected for security): HOST_PATH.
Parent directory is read-only; cannot append.
Caveats
Best-effort, not transactional. Fails closed on corruption (bad parse, missing id, non-monotonic) — operator must repair. Not a journaling tool — for plain JSONL diaries, use Write/Edit directly.
file__watch_feed(path, expiresIn?)
Register a watch on a feed. The framework fires <cast:watch> tags into the conversation when peers append rows. Your own appends are auto-suppressed.
Parameters
path[string]Path to the feed — must already exist. Call file__append_feed first to create.- optional
expiresIn[duration string]Format: number + s|m|h|d. Max 30d. Stored but not enforced — watches persist until removed.
Returns
Watch registered on PATH (lastSeenId=N[, expires ISO_TIMESTAMP]).
Watch limit reached (CURRENT/CAP). Use file__unwatch to free a slot, or raise fileWatch.maxWatchesPerChannel via Configure.
Invalid duration: "VALUE". Use format like Ns/Nm/Nh/Nd.
Caveats
Watches anchor at the feed's current end at registration time — historical rows are not delivered. Per-conversation cap defaults to 3 (configurable via fileWatch.maxWatchesPerChannel).
file__unwatch(path)
Drop a previously registered watch on a feed. Errors if the path is not currently watched in this conversation.
Parameters
path[string]Container path matching the original file__watch_feed call.
Returns
Watch on PATH removed.
No watch on PATH for this conversation.
file__list_watches()
List watches active in this conversation. Each entry shows the feed path, the last id observed, when it was registered, and (if set) when it expires.
Returns
Watches:
- PATH — last id N, registered ISO_TIMESTAMP[, expires ISO_TIMESTAMP]
No watches in this conversation.
Python (when configured)
Registered only when the agent has pip.allowed_packages declared in its manifest. There is no pip binary in the container — these tools install into the agent's persistent venv at /home/agent/.python-packages; PYTHONPATH is preconfigured.
pip__install(package, version?, upgrade?)
Install a Python package. Becomes available to all Python scripts in current and future conversations via standard import.
Parameters
package[string]Package name, e.g. "duckdb", "pandas". Must be on the agent's allowed_packages list.- optional
version[string]Version constraint, e.g. "1.2.0", ">=2.0", "<3.0,>=2.1". - optional
upgrade[boolean, default false]Upgrade to the latest version if already installed.
Returns
Installed PACKAGE VERSION. Available via `import PACKAGE` in Python scripts.
PACKAGE is already installed (version VERSION). Use upgrade: true to update.
Package "PACKAGE" is not in the allowed list. Allowed: ALLOWED_LIST
pip install failed: STDERR_TAIL
Caveats
Runs pip inside a throwaway container built from the agent image — never on the host. Cross-platform safe (wheels match the container, not the host).
pip__list()
List Python packages installed for this agent.
Returns
PACKAGE VERSION
No Python packages installed. Use pip__install to add packages.
Claude Code SDK tools
These come from the Claude Code SDK and are always present. They operate inside the container — no host reach. Cast doesn't define their signatures; see the SDK docs for parameter details.
Filesystem: Read, Write, Edit, Glob, Grep, NotebookEdit. Confined to the container's mounts.
Shell: Bash. Host secrets are stripped from subprocess environments before each call.
Web: WebSearch. Runs server-side via the SDK — works even when the container's network is sdk-only.
Sub-agents: Task, TaskOutput, TaskStop. Spawn and manage child Claude sessions inside the same container.
Planning: TodoWrite, Skill, ToolSearch. In-session scratch planning, skill invocation, deferred-tool lookup.
Disabled by Cast: WebFetch (use the web-fetch extension instead — it runs host-side with domain policy, SSRF protection, and cleaned-markdown output), AskUserQuestion (conversations are async — no interactive prompt), and Config (mutates SDK runtime including permission mode).
Extension tools
Each active extension contributes its own tools. Full per-extension signatures live on the extension's own page; this is the index.
calendar — calendar__list, calendar__get, calendar__changes, calendar__create, calendar__update, calendar__delete.
email — email__search, email__fetch, email__send, email__list_folders, email__subscribe, email__unsubscribe, email__list_subscriptions.
web-fetch — web__fetch.
whatsapp — whatsapp__chats, whatsapp__messages, whatsapp__download, whatsapp__send, whatsapp__watch, whatsapp__unwatch, whatsapp__list_watches.