Orchestration and tasks
For automatic GPT worker routing, explicit overrides and app-container deployment, see Worker harnesses.
What changes
A managed conversation agent handles the conversation and delegates substantial work to workers. Work has a persistent task record, so you can inspect progress, results, and cancellation independently of a reply.
Orchestration uses one boolean gateway.orchestration switch for all agents and connected channels. Per-agent orchestration contains conversation/task tuning. Orchestration is enabled by default. On upgrade, a missing gateway.orchestration is saved as true; an explicit false keeps legacy mode. Enabling orchestration sets and saves gateway.headless: true; interactive PTY mode is unsupported. The process supervisor supports Linux, macOS, and Windows; other platforms reject orchestration with UNSUPPORTED_PROCESS_SUPERVISOR.
Retain all existing required configuration fields. Set gateway.orchestration to false to opt out, or true to re-enable it. See orchestration settings before tuning worker limits.
Conversation intake
The optional per-agent orchestration.conversation.semanticIntake: true prepares incomplete material while waiting for a complete instruction. intakeWaitMs defaults to 2000 ms after the latest received material. More material restarts the interval; a complete instruction proceeds without waiting another interval. Even a complete instruction still waits inputDebounceMs (default 1500 ms; 0 disables batching) so consecutive chat messages are combined into one turn; see conversation processing settings. Model processing can take longer, and recording/upload-in-progress signals are not part of this timer. Without semanticIntake, only a long message split by the Telegram client is combined, so other messages start immediately.
Executable work receives a contextual acknowledgement before task creation. Channel text must be delivered first; voice acknowledgement is best-effort and does not block dispatch when synthesis is slow, suppressed or unavailable. Live voice playback also does not gate task creation. Text delivery runs independently of slow speech from earlier responses. Only the original acknowledgement text gates dispatch; optional speech-failure notices do not. Each attempted task command is checked separately, including recovered receipts, so a successful task does not hide another rejected command. A partial-failure notice distinguishes rejected commands from the current task status, since a subsequent retry may already have succeeded. If an attempted task creation/update has no committed receipt, the gateway reports that work did not start instead of promising background progress. Amendments update the relevant task. Greetings and directly answerable conversation use one normal answer without a separate task acknowledgement.
When new user input arrives before dispatch, NEW_INPUT_PENDING defers the old command so the agent can reconcile the latest instructions first. The pending dispatch survives casual replies and gateway restarts; replying alone does not clear it. A task receipt alone does not clear it: the agent must explicitly resolve the pending request, linking the corresponding task receipt, or explain that the user cancelled/replaced it or no work remains. Unrelated task successes leave the pending request intact. The tool uses conversation_intake with mode: "resolve" and a non-empty resolution for this case. When linking newly dispatched work, task_id must identify a task command committed in the same decision. This does not cancel an already-running task; use task cancellation for that.
If an ordinary reply leaves a deferred dispatch unresolved, the gateway queues one reconciliation turn with the same conversation identity and execution permissions. It references the latest persisted input by ID and reads that input within the same conversation, principal and binding, so long messages are not copied into a larger synthetic input. It does not replay the old command automatically or grant reporting-only turns execution access. A reconciliation turn cannot schedule another copy of itself; unresolved work remains available for the next user turn rather than creating an endless retry loop.
Worker tasks and Gateway-managed tasks
A Worker task runs an independent Claude Code or Codex worker. A Gateway-managed task sends a request to an existing external target, initially a safemode investigation, and lets the gateway track its durable result. Both use the same task list, status, cancellation, dependencies and completion notifications. No polling model worker is created for Gateway-managed tasks.
Discovery does not create work: capabilities_list(scope="safemode") lists only the host agent's explicitly assigned sessions. Being allowlisted alone does not expose every safemode session. See safemode setup and examples for local assignment, gateway_target, takeover and bootstrap options.
Inspect actual work
After asking an agent to perform a bounded task, inspect it from the same authorized conversation. In supported private chats, /tasks opens task controls. CLI equivalents are:
claude-gateway tasks list --agent assistant --session SESSION_ID
claude-gateway tasks show TASK_ID --agent assistant --session SESSION_ID
claude-gateway tasks watch TASK_ID --agent assistant --session SESSION_IDReplace the IDs with real identifiers from your session. The principal must belong to the session. tasks list --all includes finished work; pagination uses zero-based --page and --page-size from 1 to 100 (default 10). Ctrl+C stops watching only.
Confirm success from the retained result and relevant files or checks. CPU/I/O movement is evidence of process activity, not proof of useful progress or passing tests. A tool marked returned only means a result arrived.
Answer a task question
When work needs your decision, the Agent asks naturally in a separate message. It can combine several pending questions in one message. There are no reminder/mute buttons or system-card instructions.
Reply normally, with or without your channel's Reply action. Text, voice transcripts and attachment context go through the Agent first. Reply identifies the question being discussed; it is not automatic consent. A question such as “Can you try another approach?” stays a discussion until the Agent understands whether you want an answer, a changed goal, or more explanation. Only task_answer commits an interpreted answer; task_update handles an authorized change of goal.
Pending questions remain visible to the Agent even when you change topics. After replying to the new topic, it can ask a short separate reminder. The gateway enforces a minimum cooldown and at least three new user messages since the last question or discussion. With the default questionReminderMs=600000, cooldowns are 10, 30, then 60 minutes, capped at 60 minutes. These are eligibility limits, not a recurring message schedule. The Agent chooses whether a reminder is useful; idle conversations do not receive recurring timer reminders. A new question wakes the Agent to prepare its first message.
Say “leave it for later” to defer reminders (one hour by default), or “do not ask again” to mute that question. Discussing the question renews its cooldown. These preferences and question/message associations survive restart. Asking, discussing, deferring and muting never resume a worker or grant execution permission. Questions stop when answered, replaced or their task ends.
Explicit controls remain available for clients that intentionally bypass interpretation:
/task_question QUESTION_UUID answer Use the existing database.
/task_question QUESTION_UUID snooze
/task_question QUESTION_UUID muteThese commands and the task answer API require a current question and the correct authenticated conversation. An accepted answer is saved before work resumes when a worker slot is available.
If an automatic task report fails, its result stays pending for a later reporting attempt. Retry delays increase exponentially from five seconds to at most one hour and survive gateway restarts. These background failures remain in diagnostics rather than generating repeated chat or voice error messages. A new user message can trigger a turn immediately and still receives provider error details if that turn fails; it does not have to wait for the background retry delay. The retry delay is a fallback policy, not a prediction of the provider's quota reset time.
When a gateway restart interrupts a running worker task, the task returns to the queue instead of failing, and it runs again after the restart without a new user message. The resumed worker first verifies how far the work got (files, Git state, pushes, tags, PR and CI status, deployments and other side effects), reports that state, then finishes only the remaining steps. It does not repeat completed side effects and does not ask whether to continue. The same applies after a crash or forced kill once the previous worker process is confirmed stopped. A task resumes at most three times per instruction revision; the next interruption ends it with GATEWAY_SHUTDOWN_REPEATED. Cancelled tasks, tasks waiting for an answer, subagents and gateway-managed Browser/Computer tasks are not resumed this way. A task that an older gateway version failed during the restart (such as the process an upgrade replaces) resumes the same way when the new version starts, if the failure is less than 10 minutes old and has not been reported yet. If a progress report promises to re-run work that no task is going to run, the gateway adds a note to that reply saying that nothing is running.
A corrected task-spawn validation error does not produce a partial-failure notice when a later command in the same turn successfully queues the same work. Automatic matching requires the same title, exact brief, predecessor, context references and continuation policy. If the brief changes, the caller must copy retry_of from the rejected spawn response to explicitly identify the correction. The reference only reconciles reporting for a validation failure in the same decision; it never bypasses admission or permissions. Unrelated failures, conflicting replays, permission errors and uncertain outcomes still produce a warning. Original tool errors remain in the transcript; this changes reporting, not authorization or execution.
Corrected task_update validation, revision-conflict, and acknowledgement errors follow the same reporting rule. The successful correction must target the same task; automatic matching also requires the same instruction and mode. A changed instruction or mode requires an explicit retry_of reference. Permission failures and unrelated errors remain visible.
A finished investigation and a proposed implementation are different stages. Completion reports should identify what finished and whether a follow-up task is actually queued/running. A suggested next step is not a promise that execution has started, and read-only investigation does not authorize deployment.
Cancel and reconcile
claude-gateway tasks cancel TASK_ID --agent assistant --session SESSION_IDCancellation enters cancel_requested; it becomes cancelled after process termination is confirmed. needs_reconciliation with CLEANUP_UNCONFIRMED means cleanup is not proven and may need Retry cleanup. Stopping a host Docker client does not prove its container stopped.
Cancellation preserves files and prior side effects. Before retrying interrupted work, inspect current files, Git state, and test results. A stale progress message is not proof that later edits disappeared.
Understand time limits
The tasks.idleTimeoutMs defaults to 300000 and marks quiet workers for inspection. It does not terminate them for silence alone. tasks.maxDurationMs: 0 means no total deadline; a positive value is an explicit hard deadline. Startup and first-response budgets remain bounded.
Two limits keep a worker from staying running forever without that deadline. A final result still waiting on native background work that never reports back is accepted after tasks.backgroundGraceMs (15 minutes) of silence and marked unresolvedBackground. A worker with no new progress report for tasks.progressStaleLimitMs (2 hours) is stopped and fails with PROGRESS_STALLED. See orchestration settings.
ORCHESTRATION_DISABLED indicates legacy mode. PROFILE_INVENTORY_MISMATCH indicates a subprocess exposed tools outside its profile: restore a consistent gateway/MCP revision and retain the inventory check.
Orchestration covers text orchestration across Telegram, Discord, LINE, Slack, WhatsApp, WeChat, and API conversations. WeChat staged attachments are unsupported. Voice channel support is narrower; see voice.
Context and worker continuity
The Agent receives complete retained results for the tasks being reported in its current turn. Other tasks appear as an index with links to task_status, so old results do not have to be inserted again into every prompt. Historical command receipts retain mutation IDs, versions and question state, with a reference to current task details instead of repeated progress, workflow and result payloads. This changes prompt composition, not the stored results or user authorization.
Related work can use continue_task_id to resume a compatible Claude Code session. The pool keeps idle continuation slots while it has room, and evicts the oldest idle slot when full. Idle slots contain no running process. Expiry, changed permissions/model/configuration, different workspaces and incompatible execution profiles can require a fresh CLI session. Reusing a worker ID alone is not proof that its CLI history was resumed. Unrelated work always receives a fresh session.
Installed skill metadata is sorted deterministically, and changing previously communicated reports are supplied as turn data rather than appended to system instructions. This keeps stable prompt prefixes stable without dropping the historical messages used to avoid duplicate updates. Cache reuse still depends on the model/provider; it is not guaranteed by gateway composition alone.
Capability discovery remains separate from execution permission. The Agent can inspect the enabled tools and skills catalog and delegate worker-only capabilities. General host workers retain the broad native tool inventory, including Bash, unless an explicit internal tool policy is supplied. Narrowing an inventory must preserve the tools required to finish the task; the gateway does not assume it can hot-load missing tools into an already running CLI session.
Task state notifications are coalesced before inference. Repeated delivery of the same task version does not create another notification; active or queued conversation input prevents another automatic report from being scheduled alongside it. A completed report consumes its assigned notifications. Failed reports retry with backoff without replaying the task itself. Internal supervision can still inspect a quiet worker even when there is no user-facing update: silence does not prove that intervention is unnecessary. Reporting decisions may choose silence when no meaningful new information should be sent.
Inspect token usage
Open the admin dashboard and select View token report on a managed Agent session. The report opens in a new tab and separates Agent input handling, Agent progress/result reporting, and Worker execution. Session rows show Agent usage alongside the combined Agent/Worker total; task rows show the latest attempt’s usage and tools, matching the displayed worker/session identity. Earlier retries remain in the full report and combined session totals. Loaded tools and tools actually called are shown separately.
Turn details also show, by name, what a Claude Code turn had and used: Used skills (each Skill call, plus the skill a task was started for, such as pstack:how), the Plugins, Skills available, Agents available and MCP servers (with any server that did not connect marked by its status) from the CLI's start-up event, the Tools at session start, and Deferred tools: those whose schemas no request of the turn loaded (a tool the turn loaded through tool search is not listed). Nothing is listed by hand, so a newly installed plugin, skill or MCP server appears on its next turn. Plugin install paths are not stored. A pstack subagent's worker turn names its parent task, depth, subagent type, effort and whether it was read-only, in the session report and on the task's detail page. A queued turn, or one recorded before skills were, shows no used-skills list rather than "None". Codex has no Skill tool, so Codex turns say used skills are not recorded. Tools reached through the gateway's own tool_search/tool_call appear under used tools when called (as mcp__gateway__<tool>; a call that named the tool with that prefix again, which tool_call refuses, is shown with the name it asked for); the gateway does not record which ones a search returned without calling.
Token volume includes input, cache creation, cache reads and output. Thinking is already included in output and is not added twice. Cache creation duration is shown when the CLI reports it. These percentages describe token volume, not billing cost: cached reads and input may have different prices.
Each recorded turn includes the available request-level usage and its input/task/result context. Repeated content blocks and stream usage are deduplicated by provider message ID. A CLI turn aggregate is reconciled with request usage, not added as another request. Some providers expose only aggregate usage, so a turn total can be available without a complete request breakdown. Missing usage or tool inventory is shown as —, not an inferred zero.
Usage is persisted in the per-agent orchestration.db table token_turns for turns recorded after this feature is installed. It survives gateway restarts; earlier sessions are not retroactively assigned estimated usage. Background skill-learning reviews are accounted for separately from foreground Agent/Worker totals. See the report endpoints for programmatic access.
Use matched tasks, models, permissions and cache conditions when comparing releases. A smaller prompt or fewer repeated fields alone is not evidence of measured end-to-end savings or unchanged task quality.
Gateway execution tools in host/isolated workers use tool_search to retrieve original argument schemas and tool_call to invoke them. Discovery only searches tools already allowed by the worker policy. Calls keep the same task-ticket validation, original handler validation and cancellation path. Task reporting and memory tools remain direct; native tools retain their resolved policy. Connectors configured by an external control plane use a worker-local discovery/invocation adapter; MCP servers inherited directly from Claude Code configuration remain governed by Claude Code’s own loading behavior. This avoids depending on provider-specific support for deferred-tool reference blocks. A capability may remain available even when its full schema is not initially loaded; the dashboard distinguishes loaded schemas from the underlying tools actually called.
When every query word matches several tools, tool_search lists tools whose name matches before tools that match only in their description.
A connector can list tools a worker must confirm with the user before calling. The worker then asks through task_request_input and waits for an explicit reply. A connector can also name a local MCP server for the gateway to run. See Confirm tools before calling and Sidecar connectors.
Discovery adds a model/tool round trip on first use. Smaller schema payloads do not guarantee lower end-to-end latency or billing. Compare the same model and task with measured cache usage before concluding that a workload is cheaper. The initial implementation has protocol/fixture coverage; matched live-model A/B measurements are required to establish production savings.
The dashboard uses the same admin API key login as before. Conversations and Tasks open detail drawers with retained session records and individual worker attempts; token reports open in a separate tab. Overview displays four independently filtered charts in the configured gateway timezone, while Usage & tokens separates Agent and Worker totals. Reads run in a dedicated worker thread with bounded caches, pagination, and live updates; missing measurements are shown as —.
Overview charts
Each card has independent date controls, saved separately for each chart in this browser and dashboard path, including across reloads and new tabs: 24h / 7d / 30d / 90d, defaulting to 24h. 24h starts at 00:00 in gateway.timezone; longer ranges include today. While Overview is visible, charts refresh every 10 seconds and share requests for identical ranges. Changing one card does not change the other cards or the session list. All four charts use shared tooltips with muted labels and bold values colored to match their series. Refresh preserves keyboard focus on the same data point and updates open tooltips; if a focused point disappears, focus returns to the selected range button.
- Token activity: hourly points for today, daily points for longer ranges. Hover or focus a point for its Agent and Worker totals.
- Tokens by agent: vertical bars ranked by recorded token volume. Each bar is 32 px wide; card width determines the top 2–8 agents shown. The caption states how many are included. Bars use the same identity colors as the Agents badges. Hover over the bar or directly above it within its 32 px width, or focus the column, for the full agent name and role split.
- Tokens by model: total Agent + Worker volume grouped by the model recorded on each turn. The top five models are named; the remainder are Other models. Missing identifiers appear as Unspecified model. Hover or focus a donut segment for an immediate tooltip showing the model, tokens and share. The donut and model list share equal columns on desktop.
- Context reuse: three lines for cache read, cache write and fresh input, using the same hourly points for today and daily points for longer ranges as Token activity. Hover or focus a point for each component’s percentage of measured input and token count; percentages use that point’s cache read + cache write + fresh input, not the entire selected range. Zero input displays —, not an inferred percentage. The headline always shows today’s measured input reuse, independently of the selected chart range, compared with yesterday’s full day in percentage points. For example, 80% yesterday and 86.3% today is up 6.3 percentage points. Today is still in progress; this is not a matched-time-of-day comparison. Reuse is
cache read / (fresh input + cache write + cache read). Reused means cache read; New · saved means cache write; New · not cached means fresh input. Output and turns missing a breakdown field are excluded; the caption counts missing measurements for today. With no measured input, the percentage is — and no comparison is inferred. This measures input reuse, not a percentage of money saved.
Charts count each recorded turn once, including its latest in-progress measurement, attributed to its start time and recorded model. They do not split long-running turns across hours. Total volume includes cache reads/writes and output; background skill reviews remain separate. Queries use the isolated read-only SQLite worker and token projections, with a fallback for older rows. No model or provider call is made to collect chart data.
Dashboard session activity
The dashboard and Session token report share the same session status. After the last Agent turn ends, a conversation without active work stays Idle for one hour, even though its per-turn Claude Code process has been released. After more than one hour it shows Stopped, and both Context window cards show —. Active turns and non-terminal tasks retain their activity status. Context window retains the latest recorded measurement during the idle period; these display rules do not expire or delete conversation history or imply provider cache expiry.
Native context compaction
Use /compact in a supported chat channel or the session compact API to ask Claude Code to compact its existing session. The gateway resumes that exact transcript, requires a native compact_boundary confirmation, and leaves all gateway chat-history files intact. It never reattaches a recent-message window after compaction. Busy sessions reject compaction until their current response finishes; workers continue independently. Missing transcripts and unsupported CLI behavior return an explicit error instead of invoking a separate history summarizer. Legacy sessions require an existing idle headless process.
Installed skill metadata is kept in the stable Agent system prefix, not appended to every resumed user message. Catalog changes refresh that prefix. Worker turn reports distinguish completed, failed and cancelled outcomes from the process lifecycle and expose recorded failure codes.
Reset model context
/clear drops the agent's CLI resume mapping without deleting chat history, attachments, tasks, or worker context. Your next message starts a new Claude Code session with the latest 50 history messages (or all available messages if fewer), then later turns resume that new session. /compact instead compacts the existing CLI transcript. Wait for an active response or compaction to finish before using /clear.
Context commands across channels
/clear and /compact share the same context handlers in Telegram, Discord, LINE, Slack, WhatsApp, WhatsApp Cloud, WeChat, and the Chat API (including streaming requests and the dedicated session endpoints). They preserve gateway chat history. Telegram and the Chat API add a confirmation step (the API's /clear confirm skips it, as do the session endpoints); this does not change the operation. Discord registers native slash commands when its receiver starts. In Slack, register the slash commands in the Slack app or send them as an app mention; native slash commands cannot be used inside threads. Other chat channels accept the commands as message text. Normal channel access checks still apply.
A continuation mistakenly spawned during update intake can also recover: a later committed update must target both the captured intake task and the rejected continuation’s predecessor. Unrelated successes do not clear the warning.
Incremental context delivery
Resumed agent turns receive new or changed task snapshots rather than another copy of the entire recent-task index. A fresh CLI context starts with active/waiting tasks and currently pending reports; task_status remains available for past tasks and full original results. Receipts from completed turns are already present as tool results. Committed commands from failed/interrupted turns are supplied as recovery evidence once, without replaying their mutations.
A durable checkpoint is scoped to the conversation, authenticated principal, binding and CLI session. It stores fingerprints and IDs, not another copy of private prompts. Pending intake preserves unfinished user intent and canonical source references independently of whether their text/images have already been delivered. Repeated image references and identical image content are not attached again to the same resumed context; workers retain the original references. When an image is reused, the prompt maps its current reference to the original reference whose bytes were supplied, including after restart.
Checkpoints advance after successful, noninterrupted CLI completion. Failed turns replay unconfirmed context safely. Restart preserves checkpoints; a new/missing CLI transcript or an observed compact boundary resets delivery knowledge so required material can be supplied again. This does not trigger compaction, rewrite chat history, or truncate worker results. Stable intake and worker instructions live in the system prefix; current authorization flags remain explicit on each turn.
A task index entry carries the decision-relevant part of a running task's execution state (phase, active tools, last tool name and outcome, last progress time), not the process sample that is refreshed every 15 seconds, so a task whose only change is a new sample is not sent again; task_status still returns the full sample. Data lines with nothing in them on a turn (no pending questions, attachments, images or Computer Use evidence) are left out. The full voice reply rules are sent once per CLI context; while that context still holds them, later voice turns carry a short reminder of the output contract and the most important rules, plus the selected voice style. A compact boundary or a new CLI context sends them in full again.
These changes reduce unnecessary context growth. They do not delete duplicates already present in old transcripts, nor guarantee that unlimited genuinely new conversation stays below a fixed token count.