2026-01-03 23:44:38 +01:00
---
summary: "Agent session tools for listing sessions, fetching history, and sending cross-session messages"
read_when:
- Adding or modifying session tools
---
# Session Tools
2026-01-06 18:25:52 +00:00
Goal: small, hard-to-misuse tool set so agents can list sessions, fetch history, and send to another session.
2026-01-03 23:44:38 +01:00
## Tool Names
- `sessions_list`
- `sessions_history`
- `sessions_send`
2026-01-06 08:41:45 +01:00
- `sessions_spawn`
2026-01-03 23:44:38 +01:00
## Key Model
- Main direct chat bucket is always the literal key `"main"` .
2026-01-06 18:25:52 +00:00
- Group chats use `<provider>:group:<id>` or `<provider>:channel:<id>` .
2026-01-03 23:44:38 +01:00
- Cron jobs use `cron:<job.id>` .
- Hooks use `hook:<uuid>` unless explicitly set.
- Node bridge uses `node-<nodeId>` unless explicitly set.
`global` and `unknown` are internal-only and 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?: number` max rows (default: server default, clamp e.g. 200)
- `activeMinutes?: number` only sessions updated within N minutes
- `messageLimit?: number` 0 = no messages (default 0); >0 = include last N messages
Behavior:
- `messageLimit > 0` fetches `chat.history` per session and includes the last N messages.
- Tool results are filtered out in list output; use `sessions_history` for tool messages.
2026-01-06 08:40:21 +00:00
- When running in a **sandboxed** agent session, session tools default to **spawned-only visibility** (see below).
2026-01-03 23:44:38 +01:00
Row shape (JSON):
- `key` : session key (string)
- `kind` : `main | group | cron | hook | node | other`
- `provider` : `whatsapp | telegram | discord | signal | imessage | webchat | internal | unknown`
- `displayName` (group display label if available)
- `updatedAt` (ms)
- `sessionId`
- `model` , `contextTokens` , `totalTokens`
- `thinkingLevel` , `verboseLevel` , `systemSent` , `abortedLastRun`
- `sendPolicy` (session override if set)
2026-01-06 18:25:52 +00:00
- `lastProvider` , `lastTo`
2026-01-03 23:44:38 +01:00
- `transcriptPath` (best-effort path derived from store dir + sessionId)
- `messages?` (only when `messageLimit > 0` )
## sessions_history
Fetch transcript for one session.
Parameters:
- `sessionKey` (required)
- `limit?: number` max messages (server clamps)
- `includeTools?: boolean` (default false)
Behavior:
- `includeTools=false` filters `role: "toolResult"` messages.
- Returns messages array in the raw transcript format.
## sessions_send
Send a message into another session.
Parameters:
- `sessionKey` (required)
- `message` (required)
- `timeoutSeconds?: number` (default >0; 0 = fire-and-forget)
Behavior:
- `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; call `sessions_history` later.
- If the run fails: `{ runId, status: "error", error }` .
2026-01-04 01:15:23 +01:00
- Waits via gateway `agent.wait` (server-side) so reconnects don't drop the wait.
2026-01-04 03:04:55 +01:00
- Agent-to-agent message context is injected for the primary run.
2026-01-04 14:32:47 +00:00
- After the primary run completes, Clawdbot runs a **reply-back loop** :
2026-01-04 03:37:44 +01:00
- Round 2+ alternates between requester and target agents.
- Reply exactly `REPLY_SKIP` to stop the ping‑ pong.
- Max turns is `session.agentToAgent.maxPingPongTurns` (0– 5, default 5).
2026-01-04 14:32:47 +00:00
- Once the loop ends, Clawdbot runs the **agent‑ to‑ agent announce step** (target agent only):
2026-01-04 03:37:44 +01:00
- Reply exactly `ANNOUNCE_SKIP` to stay silent.
2026-01-06 18:25:52 +00:00
- Any other reply is sent to the target provider.
2026-01-04 03:37:44 +01:00
- Announce step includes the original request + round‑ 1 reply + latest ping‑ pong reply.
2026-01-03 23:44:38 +01:00
## Provider Field
2026-01-06 18:25:52 +00:00
- For groups, `provider` is the provider recorded on the session entry.
- For direct chats, `provider` maps from `lastProvider` .
2026-01-03 23:44:38 +01:00
- For cron/hook/node, `provider` is `internal` .
- If missing, `provider` is `unknown` .
## Security / Send Policy
2026-01-06 18:25:52 +00:00
Policy-based blocking by provider/chat type (not per session id).
2026-01-03 23:44:38 +01:00
```json
{
"session": {
"sendPolicy": {
"rules": [
{
2026-01-06 18:25:52 +00:00
"match": { "provider": "discord", "chatType": "group" },
2026-01-03 23:44:38 +01:00
"action": "deny"
}
],
"default": "allow"
}
}
}
```
Runtime override (per session entry):
- `sendPolicy: "allow" | "deny"` (unset = inherit config)
- Settable via `sessions.patch` or owner-only `/send on|off|inherit` .
Enforcement points:
- `chat.send` / `agent` (gateway)
- auto-reply delivery logic
2026-01-06 08:41:45 +01:00
## sessions_spawn
2026-01-06 18:25:52 +00:00
Spawn a sub-agent run in an isolated session and announce the result back to the requester chat provider.
2026-01-06 08:41:45 +01:00
Parameters:
- `task` (required)
- `label?` (optional; used for logs/UI)
- `timeoutSeconds?` (default 0; 0 = fire-and-forget)
- `cleanup?` (`delete|keep` , default `delete` )
Behavior:
- Starts a new `subagent:<uuid>` session with `deliver: false` .
2026-01-06 18:25:52 +00:00
- Sub-agents default to the full tool set **minus session tools** (configurable via `agent.subagents.tools` ).
2026-01-06 08:40:21 +00:00
- Sub-agents are not allowed to call `sessions_spawn` (no sub-agent → sub-agent spawning).
2026-01-06 18:25:52 +00:00
- After completion (or best-effort wait), Clawdbot runs a sub-agent **announce step** and posts the result to the requester chat provider.
2026-01-06 08:41:45 +01:00
- Reply exactly `ANNOUNCE_SKIP` during the announce step to stay silent.
2026-01-06 08:40:21 +00:00
## Sandbox Session Visibility
Sandboxed sessions can use session tools, but by default they only see sessions they spawned via `sessions_spawn` .
Config:
```json5
{
agent: {
sandbox: {
// default: "spawned"
sessionToolsVisibility: "spawned" // or "all"
}
}
}
```