Session Tools
Goal: small, hard-to-misuse tool set so agents can list sessions, fetch history, and send to another session.Tool Names
sessions_listsessions_historysessions_sendsessions_spawn
Key Model
-
Main direct chat bucket is always the literal key
"main"(resolved to the current agent’s main key). -
Group chats use
agent:<agentId>:<channel>:group:<id>oragent:<agentId>:<channel>:channel:<id>(pass the full key). - Cron jobs use
cron:<job.id>. - Hooks use
hook:<uuid>unless explicitly set. - Node sessions use
node-<nodeId>unless explicitly set.
global and unknown are reserved values and are never
listed. If
session.scope = "global", we alias it to main for all tools so callers
never see global.
sessions_list
List sessions as an array of rows. Parameters:-
kinds?: string[]filter: any of"main" | "group" | "cron" | "hook" | "node" | "other" limit?: numbermax rows (default: server default, clamp e.g. 200)activeMinutes?: numberonly sessions updated within N minutes-
messageLimit?: number0 = no messages (default 0); >0 = include last N messages
-
messageLimit > 0fetcheschat.historyper session and includes the last N messages. -
Tool results are filtered out in list output; use
sessions_historyfor tool messages. - When running in a sandboxed agent session, session tools default to spawned-only visibility (see below).
key: session key (string)kind:main | group | cron | hook | node | other-
channel:whatsapp | telegram | discord | signal | imessage | webchat | internal | unknown displayName(group display label if available)updatedAt(ms)sessionIdmodel,contextTokens,totalTokens-
thinkingLevel,verboseLevel,systemSent,abortedLastRun sendPolicy(session override if set)lastChannel,lastTo-
deliveryContext(normalized{ channel, to, accountId }when available) transcriptPath(best-effort path derived from store dir + sessionId)messages?(only whenmessageLimit > 0)
sessions_history
Fetch transcript for one session. Parameters:-
sessionKey(required; accepts session key orsessionIdfromsessions_list) limit?: numbermax messages (server clamps)includeTools?: boolean(default false)
includeTools=falsefiltersrole: "toolResult"messages.- Returns messages array in the raw transcript format.
-
When given a
sessionId, OpenClaw resolves it to the corresponding session key (missing ids error).
sessions_send
Send a message into another session. Parameters:-
sessionKey(required; accepts session key orsessionIdfromsessions_list) message(required)timeoutSeconds?: number(default >0; 0 = fire-and-forget)
-
timeoutSeconds = 0: enqueue and return{ runId, status: "accepted" }. -
timeoutSeconds > 0: wait up to N seconds for completion, then return{ runId, status: "ok", reply }. -
If wait times out:
{ runId, status: "timeout", error }. Run continues; callsessions_historylater. - If the run fails:
{ runId, status: "error", error }. -
Announce delivery runs after the primary run completes and is best-effort;
status: "ok"does not guarantee the announce was delivered. -
Waits via gateway
agent.wait(server-side) so reconnects don’t drop the wait. - Agent-to-agent message context is injected for the primary run.
-
After the primary run completes, OpenClaw runs a reply-back loop:
- Round 2+ alternates between requester and target agents.
- Reply exactly
REPLY_SKIPto stop the ping‑pong. - Max turns is
session.agentToAgent.maxPingPongTurns(0–5, default 5).
-
Once the loop ends, OpenClaw runs the agent‑to‑agent announce step (target
agent only):
- Reply exactly
ANNOUNCE_SKIPto stay silent. - Any other reply is sent to the target channel.
- Announce step includes the original request + round‑1 reply + latest ping‑pong reply.
- Reply exactly
Channel Field
- For groups,
channelis the channel recorded on the session entry. - For direct chats,
channelmaps fromlastChannel. - For cron/hook/node,
channelisinternal. - If missing,
channelisunknown.
Security / Send Policy
Policy-based blocking by channel/chat type (not per session id).sendPolicy: "allow" | "deny"(unset = inherit config)-
Settable via
sessions.patchor owner-only/send on|off|inherit(standalone message).
chat.send/agent(gateway)- auto-reply delivery logic
sessions_spawn
Spawn a sub-agent run in an isolated session and announce the result back to the requester chat channel. Parameters:task(required)label?(optional; used for logs/UI)agentId?(optional; spawn under another agent id if allowed)model?(optional; overrides the sub-agent model; invalid values error)-
runTimeoutSeconds?(default 0; when set, aborts the sub-agent run after N seconds) cleanup?(delete|keep, defaultkeep)
-
agents.list[].subagents.allowAgents: list of agent ids allowed viaagentId(["*"]to allow any). Default: only the requester agent.
-
Use
agents_listto discover which agent ids are allowed forsessions_spawn.
-
Starts a new
agent:<agentId>:subagent:<uuid>session withdeliver: false. -
Sub-agents default to the full tool set minus session tools (configurable via
tools.subagents.tools). -
Sub-agents are not allowed to call
sessions_spawn(no sub-agent → sub-agent spawning). -
Always non-blocking: returns
{ status: "accepted", runId, childSessionKey }immediately. - After completion, OpenClaw runs a sub-agent announce step and posts the result to the requester chat channel.
- Reply exactly
ANNOUNCE_SKIPduring the announce step to stay silent. -
Announce replies are normalized to
Status/Result/Notes;Statuscomes from runtime outcome (not model text). -
Sub-agent sessions are auto-archived after
agents.defaults.subagents.archiveAfterMinutes(default: 60). - Announce replies include a stats line (runtime, tokens, sessionKey/sessionId, transcript path, and optional cost).
Sandbox Session Visibility
Sandboxed sessions can use session tools, but by default they only see sessions they spawned viasessions_spawn.
Config: