Repository navigation
Releases: moeen-mahmud/dispach
Release list
v0.2.0
- Ahead of OpenClaw on all 11 benchmarked models, level with or ahead of Hermes on 8, and the cheapest of the three on 10 (benchmarks).
- Pluggable model transports with Bedrock, MCP, subagents, a larger HTTP API for embedders, and secrets kept out of the agent's reach.
- A 0.1.3 agent and store boot unchanged. Highlights and the upgrade path: What's new in 0.2.0.
Every change since 0.1.3, consolidated from the 0.2.0 pre-releases listed below. Rooms, stand-ins and team memory ship as experimental, API-only.
Upgrading from 0.1.3
- Breaking: a plugin declares
dispachApi: "^0.2". One on^0.1is refused at boot withplugin_api_mismatch. - Breaking: a reload during a turn answers
202 pendinginstead of409, and the turn finishes on the old settings. - Breaking:
GET /v1/agents/:idon a stopped agent returns itsstatus: "disabled"row instead of 404. Routes that act on it are still 404. - Breaking: a scheduled run ending
timeout,max_steps,no_progressorerroris recorded as an error, notok. - An agent
idmay no longer start with~. - Store migrations 18–31 run on first boot, with no down-migration. Back up
store.dbfirst. - The first turn after upgrading misses the prompt cache once, because workspace files now reach the model labelled with their names.
- Nothing in an existing
agent.yamlhas to change: a 0.1.3 agent and store boot on 0.2.0 as they are, history included. - An agent generated by 0.2.0
initusesdialect: nativewhere the model calls tools natively. An existing manifest keeps its dialect, and the schema default is stillnlt.
Models
model.<role>.apiselects a transport (defaultchat-completions);defineModelTransportregisters one from a plugin.baseUrlis required only for chat-completions.- AWS Bedrock:
api: bedrock-converse, credentials from the AWS default chain and never the manifest, with prompt caching, native tools and cache-read/write usage. model.<role>.fallbacks: other models tried in order when the endpoint fails before any output. Never on a 4xx the caller caused, never on a 403.- Signed thinking is replayed with tool results, Claude 5.x included.
reasoningEffortgainsxhighandmax. imagesonPOST /messages, and photos sent on channels, reach a model with vision. A model without it refuses withmodel_no_vision.- A refused reply (a safety classifier, a guardrail, a
content_filterfinish) ends the turn asmodel_refusedinstead of an empty answer. - Capability rows for Amazon Nova, Claude 5.x, Claude Haiku 5.5 and
gpt-6*(the last reported, not verified;model probesettles it). - Only byte-stable context slots are system messages. The volatile tier, the reminder and recall are user messages, each ending with a line saying the person's message follows, so a memory write no longer empties OpenAI's prompt cache.
- Claude reached through OpenRouter gets
cache_controlmarkers over chat-completions. - Capability rows for GLM 5.3 and hosted
qwen/qwen3.5*(262,144 tokens; localqwen3.5*keeps 32,768).
Tools
- MCP:
tools.providers.mcpserves tools from remote servers over Streamable HTTP, pinned by name as<server>__<tool>and resolved from a cache at boot. A server added from settings works with no restart. - Subagents:
subagents:routes a tool call to a throwaway child of the same agent, and the parent reads its artifact instead of the raw output.model.subagentruns children on a cheaper model. - A tool pinned with
config_setworks without a restart. - A tool whose schema cannot be loaded is left out and warned about (
tool_schema_unsupported). It no longer refuses the agent. - Plain-value unions in tool schemas are accepted, and under NLT a field taking a list of objects keeps its objects.
- A tool result cut to fit
observationMaxTokensis stored whole and readable withartifact_read. limits.noProgress.sameTool: Nends a turn after N calls to one tool, whatever the arguments.tools.eventDetail: redactedadds a call's arguments and the start of its output to tool events, with secrets replaced.POST /v1/agents/:id/tools/refreshfetches catalogues now and reloads only if something changed.- Web:
tools.providers.web.baseUrlpoints the search backend at a relay. Every search emitstool.usage, and any tool can report spend throughToolContext.meter. - A built-in pinned again under an MCP namespace (
<server>__now) leaves the catalogue, withtool_builtin_shadowednaming both.
Agent loop
- A step that would end the turn silent, on a promise (I'll do X), or claiming a save or send that never ran gets one framed runtime note and one more step. Once per turn.
- The turn's trace follows its input for every transport, not only Claude thinking and Bedrock.
- Without
context.observationMaxTokens, a tool observation may take a quarter of the window (2,000 to 32,000 tokens) instead of a flat 2,000. limits.noProgress.identicalCallslets an identical call through, at most twice, after a failure the tool itself called temporary.- NLT: identical consecutive blocks run once, and
ACTION:glued to a sentence earns a repair instead of becoming the reply.
Security
file_readandgrepnever read a secret:.envand key files, credential directories, a process'senviron, symlinks included.- A path rule in
tools.policymatches the normalised path, soworkspace/../.envno longer walks pastdeny: ["file_read(.env)"]. tools.providers.system.env: scrubkeeps the runtime's secrets out of whatexecand skill scripts see. Off by default.tools.providers.system.confineReads: trueconfines the file tools to the agent's directory and its write roots. Off by default.skills.trusted: [names]: only these skills' scripts become tools.X_FILEsetsXfrom a file when the CLI starts, so the value never enters the process environment.- The agent's
config_setcannot set any provider'sbaseUrl,env,confineReadsorpersonalflag, norskills.trusted. - The Slack bot token is sent only to
https://files.slack.com/files-pri/…, and the regexes run on untrusted message text are linear. - A key scoped to sessions reaches only their turns (
GET,/streamand/stopby turn id) and their pending approvals, and answering an approval checks its agent and session.
HTTP API
- Agent templates (
GET /v1/templates,POST /v1/agents {template, vars},PATCH /v1/agents/:id/vars) and per-agent secrets (GET/PUT /v1/agents/:id/secrets). - Every model call is metered:
GET /v1/usageandGET /v1/agents/:id/turns. A call has an id a biller can debit on. - Outbound webhooks, signed with Standard Webhooks:
/v1/webhooks. limits.maxConcurrentTurnsandlimits.tokensrefuse a turn with429;GET /v1/activityreports idleness and the next schedule.PATCH /configremoves a field ({path, remove: true}), applies a batch in one write (changes[]), and writes nothing for a value already there (changed: false).POST /messagestakesroleandruntimeNote, your application's note about the message, shown to the model as not the person's.POST /v1/agents/:id/deliveriessends exact text on a channel through the outbox, with no turn.DELETE /v1/agents/:id?confirm=<id>deletes an agent. An agent that will not load can be repaired over the API (failed,PUT …/workspace/:file).GET /v1/backupstreams the silo as a tar.gz.include=home,env,gitwiden it, and restoring is documented in the wire spec.- A turn's result and
turn.endcarryfinalText, the last step's prose.delivery.reply: finalsends only that to a channel. Errors carry an optionaldetail, the provider's own words. dispach/clientanddispach/wireship self-contained type declarations.inkandreactare optional, so a client-only install carries no terminal UI.
Memory and context
- A note saved with
memory_write, or an edit toMEMORY.md/USER.md, reaches every session on the next turn. It used to wait for a restart. memory_forgetlists notes by query and deletes exactly the ids given, redacting them from past messages too.POST /v1/agents/:id/sessions/:key/recall {recall: false}takes a conversation out of recall without deleting it.memory.recalledlists what a prompt recalled.context.modelIdentity: hiddenkeeps the model, endpoint and key variable out of the agent's prompt andconfig_read.- A workspace file reaching the model with an unrendered
{{vars.…}}is warned about (workspace_unrendered_var).
Operating
- Kubernetes:
docs/17-KUBERNETES.mdandexamples/kubernetes/silo.yaml. The store refuses to open on NFS or EFS, andDISPACH_DRAIN_MSlets a stop wait for running turns. limits.reloadHoldMs; a manifest broken on disk is refused before the running agent is torn down.- Every agent in a sandbox shares one host token, so
run,stopandstartno longer get a 401 for every agent but the first. servelists an agent it cannot build instead of exiting for all of them.- The image includes
ffmpeg. - The image size is reported on every push and no longer gates it.
init
- Writes
dialect: nativewhere the registry knows the model calls tools natively,nltotherwise. - Asks the endpoint for its context window when someone is at the keyboard, or with
--measure-window, and writes it tocontext.window.--yesand a pipe still reach no network. - No longer writes a
temperature. - The generated rules no longer ask before a send the person requested (deleting still confirms), and the third-party rule applies only when the person has not said what to share.
Experimental
API-only, with no TUI or web screens yet, and either multiplayer or never run against a real tenant o...
v0.2.0-pilot.17
A pre-release for the multiplayer runtime: one silo per user, run by a control plane.
Since 0.2.0-pilot.16
- Bedrock: Claude Haiku 5.5 thinks through adaptive effort (
thinking.type: adaptive+output_config.effort) like the other Claude 5.5 models, and is registered with its 1M window. It was sent a token budget like Haiku 4.5, which it refuses with aValidationExceptionon every turn that had thinking on.
Since 0.2.0-pilot.15
- A pinned tool whose schema cannot be loaded no longer refuses the agent. That tool is left out, warned about as
tool_schema_unsupportedwith its slug and the keyword, and the model is told it is unavailable; the rest of the agent loads. One upstream Composio change had refused every reload of every agent pinning it. A provider reports such tools through the new optionalToolProvider.refused().composio_searchmarks such a tooln/awith the same reason, so the agent does not pin it. - Unions of plain values in a tool schema (
anyOf/oneOfof string, number, integer and boolean, or atypelist) are accepted: the native dialect sendstype: [...], NLT names every type, and a value already of a listed type is kept as written. A union with an object or a list in it,allOf,notand$refare still refused. PATCH /configsetsmodel.mainas a whole role (transport, id, endpoint, key variable, capabilities) in one write and one reload, person-only;GET /configreports it,baseUrland theapiKeyEnvname included.- A
changes[]batch with unknown paths names every one with its index (changes.1.path) and writes nothing.
Since 0.2.0-pilot.14
PATCH /v1/agents/:id/configwith a value already in the file writes nothing and does not reload the agent; the reply sayschanged: false, reloaded: false. A configuration applied in full on every sync no longer reloads the agent once per setting.PATCH /configtakes{changes: [{path, value} | {path, remove: true}, …]}: several settings checked together, written once, one reload. Any refusal writes none. The single{path, value}body is unchanged. The client hassetConfigs(changes), andsetConfig's result now carrieschangedandreloaded.- Removing a block's last key removes the block, so removing
limits.noProgress.sameToolno longer leaves an emptynoProgress:that would not load. limits.noProgressandlimits.noProgress.sameToolare settable by a person throughPATCH /configand theconfigcommand.config_setcannot change them.media.speech: a voice note is answered with the text reply and then a voice note of it. Typed messages are answered in text only, as before. The provider isaws(Amazon Polly:options {region, voiceId, engine}; needspolly:SynthesizeSpeech) oropenai(/audio/speech). Voice notes go out on WhatsApp and Telegram, an audio file on Slack, and none on Teams. A long reply becomes several notes. Each note emitsmedia.result {kind: "speech", characters}.- Amazon Transcribe voice notes in formats other than Ogg/Opus and FLAC (Slack WebM, Teams M4A, MP3) are decoded with
ffmpegfirst. They were refused before. The image now includesffmpeg. turn.startcarriesinputKind: "voice"when the input was a transcribed voice note.- Each workspace file now reaches the model labelled with its name, in the model's delimiter style (
<file name="SOUL.md" tier="static">,## SOUL.md, orSOUL.md:). The configuration block gains acontext filesrow naming the files, andconfig_read's summary listscontext.soul.file,context.static,context.volatileandcontext.reminder(read-only) with the same note. Asked whether its files were loading, an agent saw no names, said they were not, and re-read them untilno_progress. The first turn after upgrading misses the prompt cache once, because the cached prefix changed. subagentsis settable as a whole list by a person or embedder throughPATCH /configandchanges[], checked as at load (subagent_tool_not_pinnedand the rest). The agent'sconfig_setcannot set it. Any edit that unpins a slug a child uses is now refused instead of breaking the next boot.subagents[].timeoutMsbounds a child's routed calls instead oflimits.toolTimeoutMs, so a slow child can get minutes while every other tool keeps its own bound.- Bedrock: OpenAI models (
openai.*, GPT-6 Luna and the rest) no longer repeat a tool call untilno_progress. A turn's own calls and results now follow the person's message, as they already did for Claude and Nova. Before, the tool result and the restated question were sent as one message, and the model read it as a new request. - A member's connected apps are theirs alone. Every Composio tool, and the tools of an MCP server declared
personal: true, are left out of any turn that does not act for the agent's assigned owner: another member asking, a delegation from their agent, a stand-in, or a channel sender who is not the owner. A call to one is refused astool_personal, with atool.gatedevent.PUT /v1/agents/:id/assigneetakeschannelIds, the owner's own channel senders, so the owner's WhatsApp keeps their apps (store migration 30). Unassigned agents and turns with no person are unchanged. - An agent that will not load can be repaired over the API, instead of answering 404 everywhere.
GET /v1/agents/:idsaysfailedwith the load error, ornot_running.GET/PATCH /configandPATCH /varsedit its files, answeringapplied: falseuntilPOST /start. The newPUT /v1/agents/:id/workspace/:filereplaces a declared workspace file. On a running agent it reloads, and the old text is put back if the new one would not load.context.budgets.*is settable by a person. - media-aws (Transcribe, Polly, Nova Canvas) reads a container-credentials endpoint itself, as Bedrock does. A silo's
169.254.170.2:4000endpoint failed every voice note with "not a valid container metadata service hostname", and the endpoint's own refusal code (credit_exhausted) is now the media error's code. - media-aws: an access refusal's hint now says in plain words what the agent's credentials do not allow (voice notes, spoken replies, image generation), then the one permission to grant. The old hint mentioned "the pod's service account", and agents repeated it to people.
context.modelIdentity: hidden(defaultshown): the agent's prompt andconfig_readno longer name its model, endpoint, transport or key variable, nor its media models and providers. Everything else stays readable and settable. Person-only. Events and the API are unchanged.memory_forget, a local tool:{query}lists the agent's notes containing every word, with ids, and deletes nothing;{ids}deletes exactly those from the carried file and the archives, or from the space for the space writer. Past conversation messages the asking person said (or the agent replied in their turns) are listed too and redacted in place, along with the conversation that asked and any tool call or result elsewhere that carries the forgotten text (the call keeps its shape), the turn whosememory_writesaved a deleted note (its reply included), and the silo's own webhook delivery log; the memory index is re-read at once; recall, a rebuild and an export cannot bring them back. Refused in rooms and stand-ins. Emitsmemory.forgotten {scope, count, messages?}.initpins it; it is not added topolicy.allow.- A turn records the participant it was taken for (
turns.participant_id, migration 31). - To stop an earlier conversation from being recalled (
includeHistory), usePOST /v1/agents/:id/sessions/:key/recall {"recall": false}, which keeps the history (pilot.10), orDELETE /v1/agents/:id/sessions/:key, which removes it and its index entries. A note saved inMEMORY.mdis a file and has to be edited.
Since 0.2.0-pilot.13
- Bedrock: Nova no longer fails on the second call of a native tool turn with "extraneous key [cachePoint] is not permitted". pilot.13's rolling cache point is left out of a Nova message that carries a tool result; Claude keeps it.
finalTexton a turn's result and onturn.end: the last step's prose alone. The reply still joins every step's, so a lead-in a model repeats before each tool call ("Yes, Outlook. Let me try…") appears once infinalText.delivery.reply: final(settable withPATCH /configand by the agent'sconfig_set) makes a channel reply (WhatsApp, Telegram, Slack, Teams) the last step's prose alone. The default,all, keeps every step's joined, as before.- Errors take an optional
detail: a provider's own words, verbatim. Bedrock now puts AWS's text there instead of inmessage, so an access refusal's assumed-role ARN is no longer in what an embedder shows people. A failed turn's record carries it aserrorDetail(store migration 29). channels[].roleruns a channel's turns on a model role declared undermodel:, e.g. WhatsApp on a cheaper model than the web chat. Absent ismain. A role that is not declared refuses the manifest.- The reminder tier now opens with a line saying it is the agent's own instructions and the person did not write it. On Bedrock, any system message after the start of the conversation is sent fenced in
<system>…</system>rather than as bare user text. A model had read an unframed reminder as something the person pasted. - A workspace file that reaches the model with an unrendered
{{vars.…}}placeholder is reported asworkspace_unrendered_var, on the agent's warnings and byvalidate. A placeholder inside an HTML comment, which the model never sees, is not. tools.providers.system.confineReads: trueconfinesfile_read,globandgrepto the agent's directory and itswriteRoots, a symlink pointing out included, so in a silo one agent cannot read another's notes. Off by default;config_setcannot set it;execis not bound by it.skills.trusted: [names]: only these skills' scripts become too...
v0.2.0-pilot.16
A pre-release for the multiplayer runtime: one silo per user, run by a control plane.
Since 0.2.0-pilot.15
- A pinned tool whose schema cannot be loaded no longer refuses the agent. That tool is left out, warned about as
tool_schema_unsupportedwith its slug and the keyword, and the model is told it is unavailable; the rest of the agent loads. One upstream Composio change had refused every reload of every agent pinning it. A provider reports such tools through the new optionalToolProvider.refused().composio_searchmarks such a tooln/awith the same reason, so the agent does not pin it. - Unions of plain values in a tool schema (
anyOf/oneOfof string, number, integer and boolean, or atypelist) are accepted: the native dialect sendstype: [...], NLT names every type, and a value already of a listed type is kept as written. A union with an object or a list in it,allOf,notand$refare still refused. PATCH /configsetsmodel.mainas a whole role (transport, id, endpoint, key variable, capabilities) in one write and one reload, person-only;GET /configreports it,baseUrland theapiKeyEnvname included.- A
changes[]batch with unknown paths names every one with its index (changes.1.path) and writes nothing.
Since 0.2.0-pilot.14
PATCH /v1/agents/:id/configwith a value already in the file writes nothing and does not reload the agent; the reply sayschanged: false, reloaded: false. A configuration applied in full on every sync no longer reloads the agent once per setting.PATCH /configtakes{changes: [{path, value} | {path, remove: true}, …]}: several settings checked together, written once, one reload. Any refusal writes none. The single{path, value}body is unchanged. The client hassetConfigs(changes), andsetConfig's result now carrieschangedandreloaded.- Removing a block's last key removes the block, so removing
limits.noProgress.sameToolno longer leaves an emptynoProgress:that would not load. limits.noProgressandlimits.noProgress.sameToolare settable by a person throughPATCH /configand theconfigcommand.config_setcannot change them.media.speech: a voice note is answered with the text reply and then a voice note of it. Typed messages are answered in text only, as before. The provider isaws(Amazon Polly:options {region, voiceId, engine}; needspolly:SynthesizeSpeech) oropenai(/audio/speech). Voice notes go out on WhatsApp and Telegram, an audio file on Slack, and none on Teams. A long reply becomes several notes. Each note emitsmedia.result {kind: "speech", characters}.- Amazon Transcribe voice notes in formats other than Ogg/Opus and FLAC (Slack WebM, Teams M4A, MP3) are decoded with
ffmpegfirst. They were refused before. The image now includesffmpeg. turn.startcarriesinputKind: "voice"when the input was a transcribed voice note.- Each workspace file now reaches the model labelled with its name, in the model's delimiter style (
<file name="SOUL.md" tier="static">,## SOUL.md, orSOUL.md:). The configuration block gains acontext filesrow naming the files, andconfig_read's summary listscontext.soul.file,context.static,context.volatileandcontext.reminder(read-only) with the same note. Asked whether its files were loading, an agent saw no names, said they were not, and re-read them untilno_progress. The first turn after upgrading misses the prompt cache once, because the cached prefix changed. subagentsis settable as a whole list by a person or embedder throughPATCH /configandchanges[], checked as at load (subagent_tool_not_pinnedand the rest). The agent'sconfig_setcannot set it. Any edit that unpins a slug a child uses is now refused instead of breaking the next boot.subagents[].timeoutMsbounds a child's routed calls instead oflimits.toolTimeoutMs, so a slow child can get minutes while every other tool keeps its own bound.- Bedrock: OpenAI models (
openai.*, GPT-6 Luna and the rest) no longer repeat a tool call untilno_progress. A turn's own calls and results now follow the person's message, as they already did for Claude and Nova. Before, the tool result and the restated question were sent as one message, and the model read it as a new request. - A member's connected apps are theirs alone. Every Composio tool, and the tools of an MCP server declared
personal: true, are left out of any turn that does not act for the agent's assigned owner: another member asking, a delegation from their agent, a stand-in, or a channel sender who is not the owner. A call to one is refused astool_personal, with atool.gatedevent.PUT /v1/agents/:id/assigneetakeschannelIds, the owner's own channel senders, so the owner's WhatsApp keeps their apps (store migration 30). Unassigned agents and turns with no person are unchanged. - An agent that will not load can be repaired over the API, instead of answering 404 everywhere.
GET /v1/agents/:idsaysfailedwith the load error, ornot_running.GET/PATCH /configandPATCH /varsedit its files, answeringapplied: falseuntilPOST /start. The newPUT /v1/agents/:id/workspace/:filereplaces a declared workspace file. On a running agent it reloads, and the old text is put back if the new one would not load.context.budgets.*is settable by a person. - media-aws (Transcribe, Polly, Nova Canvas) reads a container-credentials endpoint itself, as Bedrock does. A silo's
169.254.170.2:4000endpoint failed every voice note with "not a valid container metadata service hostname", and the endpoint's own refusal code (credit_exhausted) is now the media error's code. - media-aws: an access refusal's hint now says in plain words what the agent's credentials do not allow (voice notes, spoken replies, image generation), then the one permission to grant. The old hint mentioned "the pod's service account", and agents repeated it to people.
context.modelIdentity: hidden(defaultshown): the agent's prompt andconfig_readno longer name its model, endpoint, transport or key variable, nor its media models and providers. Everything else stays readable and settable. Person-only. Events and the API are unchanged.memory_forget, a local tool:{query}lists the agent's notes containing every word, with ids, and deletes nothing;{ids}deletes exactly those from the carried file and the archives, or from the space for the space writer. Past conversation messages the asking person said (or the agent replied in their turns) are listed too and redacted in place, along with the conversation that asked and any tool call or result elsewhere that carries the forgotten text (the call keeps its shape), the turn whosememory_writesaved a deleted note (its reply included), and the silo's own webhook delivery log; the memory index is re-read at once; recall, a rebuild and an export cannot bring them back. Refused in rooms and stand-ins. Emitsmemory.forgotten {scope, count, messages?}.initpins it; it is not added topolicy.allow.- A turn records the participant it was taken for (
turns.participant_id, migration 31). - To stop an earlier conversation from being recalled (
includeHistory), usePOST /v1/agents/:id/sessions/:key/recall {"recall": false}, which keeps the history (pilot.10), orDELETE /v1/agents/:id/sessions/:key, which removes it and its index entries. A note saved inMEMORY.mdis a file and has to be edited.
Since 0.2.0-pilot.13
- Bedrock: Nova no longer fails on the second call of a native tool turn with "extraneous key [cachePoint] is not permitted". pilot.13's rolling cache point is left out of a Nova message that carries a tool result; Claude keeps it.
finalTexton a turn's result and onturn.end: the last step's prose alone. The reply still joins every step's, so a lead-in a model repeats before each tool call ("Yes, Outlook. Let me try…") appears once infinalText.delivery.reply: final(settable withPATCH /configand by the agent'sconfig_set) makes a channel reply (WhatsApp, Telegram, Slack, Teams) the last step's prose alone. The default,all, keeps every step's joined, as before.- Errors take an optional
detail: a provider's own words, verbatim. Bedrock now puts AWS's text there instead of inmessage, so an access refusal's assumed-role ARN is no longer in what an embedder shows people. A failed turn's record carries it aserrorDetail(store migration 29). channels[].roleruns a channel's turns on a model role declared undermodel:, e.g. WhatsApp on a cheaper model than the web chat. Absent ismain. A role that is not declared refuses the manifest.- The reminder tier now opens with a line saying it is the agent's own instructions and the person did not write it. On Bedrock, any system message after the start of the conversation is sent fenced in
<system>…</system>rather than as bare user text. A model had read an unframed reminder as something the person pasted. - A workspace file that reaches the model with an unrendered
{{vars.…}}placeholder is reported asworkspace_unrendered_var, on the agent's warnings and byvalidate. A placeholder inside an HTML comment, which the model never sees, is not. tools.providers.system.confineReads: trueconfinesfile_read,globandgrepto the agent's directory and itswriteRoots, a symlink pointing out included, so in a silo one agent cannot read another's notes. Off by default;config_setcannot set it;execis not bound by it.skills.trusted: [names]: only these skills' scripts become tools, andGET /v1/agents/:id/skillsmarks each skilltrusted. Any other skill, such as one a person uploaded or a community skill, is still used for its steps, and its scripts are listed as documentation only. Absent, every skill's scripts run, as before.config_setcannot set it.- A tool pinned with
config_setworks without a ...
v0.2.0-pilot.15
A pre-release for the multiplayer runtime: one silo per user, run by a control plane.
Since 0.2.0-pilot.14
PATCH /v1/agents/:id/configwith a value already in the file writes nothing and does not reload the agent; the reply sayschanged: false, reloaded: false. A configuration applied in full on every sync no longer reloads the agent once per setting.PATCH /configtakes{changes: [{path, value} | {path, remove: true}, …]}: several settings checked together, written once, one reload. Any refusal writes none. The single{path, value}body is unchanged. The client hassetConfigs(changes), andsetConfig's result now carrieschangedandreloaded.- Removing a block's last key removes the block, so removing
limits.noProgress.sameToolno longer leaves an emptynoProgress:that would not load. limits.noProgressandlimits.noProgress.sameToolare settable by a person throughPATCH /configand theconfigcommand.config_setcannot change them.media.speech: a voice note is answered with the text reply and then a voice note of it. Typed messages are answered in text only, as before. The provider isaws(Amazon Polly:options {region, voiceId, engine}; needspolly:SynthesizeSpeech) oropenai(/audio/speech). Voice notes go out on WhatsApp and Telegram, an audio file on Slack, and none on Teams. A long reply becomes several notes. Each note emitsmedia.result {kind: "speech", characters}.- Amazon Transcribe voice notes in formats other than Ogg/Opus and FLAC (Slack WebM, Teams M4A, MP3) are decoded with
ffmpegfirst. They were refused before. The image now includesffmpeg. turn.startcarriesinputKind: "voice"when the input was a transcribed voice note.- Each workspace file now reaches the model labelled with its name, in the model's delimiter style (
<file name="SOUL.md" tier="static">,## SOUL.md, orSOUL.md:). The configuration block gains acontext filesrow naming the files, andconfig_read's summary listscontext.soul.file,context.static,context.volatileandcontext.reminder(read-only) with the same note. Asked whether its files were loading, an agent saw no names, said they were not, and re-read them untilno_progress. The first turn after upgrading misses the prompt cache once, because the cached prefix changed. subagentsis settable as a whole list by a person or embedder throughPATCH /configandchanges[], checked as at load (subagent_tool_not_pinnedand the rest). The agent'sconfig_setcannot set it. Any edit that unpins a slug a child uses is now refused instead of breaking the next boot.subagents[].timeoutMsbounds a child's routed calls instead oflimits.toolTimeoutMs, so a slow child can get minutes while every other tool keeps its own bound.- Bedrock: OpenAI models (
openai.*, GPT-6 Luna and the rest) no longer repeat a tool call untilno_progress. A turn's own calls and results now follow the person's message, as they already did for Claude and Nova. Before, the tool result and the restated question were sent as one message, and the model read it as a new request. - A member's connected apps are theirs alone. Every Composio tool, and the tools of an MCP server declared
personal: true, are left out of any turn that does not act for the agent's assigned owner: another member asking, a delegation from their agent, a stand-in, or a channel sender who is not the owner. A call to one is refused astool_personal, with atool.gatedevent.PUT /v1/agents/:id/assigneetakeschannelIds, the owner's own channel senders, so the owner's WhatsApp keeps their apps (store migration 30). Unassigned agents and turns with no person are unchanged. - An agent that will not load can be repaired over the API, instead of answering 404 everywhere.
GET /v1/agents/:idsaysfailedwith the load error, ornot_running.GET/PATCH /configandPATCH /varsedit its files, answeringapplied: falseuntilPOST /start. The newPUT /v1/agents/:id/workspace/:filereplaces a declared workspace file. On a running agent it reloads, and the old text is put back if the new one would not load.context.budgets.*is settable by a person. - media-aws (Transcribe, Polly, Nova Canvas) reads a container-credentials endpoint itself, as Bedrock does. A silo's
169.254.170.2:4000endpoint failed every voice note with "not a valid container metadata service hostname", and the endpoint's own refusal code (credit_exhausted) is now the media error's code. - media-aws: an access refusal's hint now says in plain words what the agent's credentials do not allow (voice notes, spoken replies, image generation), then the one permission to grant. The old hint mentioned "the pod's service account", and agents repeated it to people.
context.modelIdentity: hidden(defaultshown): the agent's prompt andconfig_readno longer name its model, endpoint, transport or key variable, nor its media models and providers. Everything else stays readable and settable. Person-only. Events and the API are unchanged.memory_forget, a local tool:{query}lists the agent's notes containing every word, with ids, and deletes nothing;{ids}deletes exactly those from the carried file and the archives, or from the space for the space writer. Past conversation messages the asking person said (or the agent replied in their turns) are listed too and redacted in place, along with the conversation that asked and any tool call or result elsewhere that carries the forgotten text (the call keeps its shape), the turn whosememory_writesaved a deleted note (its reply included), and the silo's own webhook delivery log; the memory index is re-read at once; recall, a rebuild and an export cannot bring them back. Refused in rooms and stand-ins. Emitsmemory.forgotten {scope, count, messages?}.initpins it; it is not added topolicy.allow.- A turn records the participant it was taken for (
turns.participant_id, migration 31). - To stop an earlier conversation from being recalled (
includeHistory), usePOST /v1/agents/:id/sessions/:key/recall {"recall": false}, which keeps the history (pilot.10), orDELETE /v1/agents/:id/sessions/:key, which removes it and its index entries. A note saved inMEMORY.mdis a file and has to be edited.
Since 0.2.0-pilot.13
- Bedrock: Nova no longer fails on the second call of a native tool turn with "extraneous key [cachePoint] is not permitted". pilot.13's rolling cache point is left out of a Nova message that carries a tool result; Claude keeps it.
finalTexton a turn's result and onturn.end: the last step's prose alone. The reply still joins every step's, so a lead-in a model repeats before each tool call ("Yes, Outlook. Let me try…") appears once infinalText.delivery.reply: final(settable withPATCH /configand by the agent'sconfig_set) makes a channel reply (WhatsApp, Telegram, Slack, Teams) the last step's prose alone. The default,all, keeps every step's joined, as before.- Errors take an optional
detail: a provider's own words, verbatim. Bedrock now puts AWS's text there instead of inmessage, so an access refusal's assumed-role ARN is no longer in what an embedder shows people. A failed turn's record carries it aserrorDetail(store migration 29). channels[].roleruns a channel's turns on a model role declared undermodel:, e.g. WhatsApp on a cheaper model than the web chat. Absent ismain. A role that is not declared refuses the manifest.- The reminder tier now opens with a line saying it is the agent's own instructions and the person did not write it. On Bedrock, any system message after the start of the conversation is sent fenced in
<system>…</system>rather than as bare user text. A model had read an unframed reminder as something the person pasted. - A workspace file that reaches the model with an unrendered
{{vars.…}}placeholder is reported asworkspace_unrendered_var, on the agent's warnings and byvalidate. A placeholder inside an HTML comment, which the model never sees, is not. tools.providers.system.confineReads: trueconfinesfile_read,globandgrepto the agent's directory and itswriteRoots, a symlink pointing out included, so in a silo one agent cannot read another's notes. Off by default;config_setcannot set it;execis not bound by it.skills.trusted: [names]: only these skills' scripts become tools, andGET /v1/agents/:id/skillsmarks each skilltrusted. Any other skill, such as one a person uploaded or a community skill, is still used for its steps, and its scripts are listed as documentation only. Absent, every skill's scripts run, as before.config_setcannot set it.- A tool pinned with
config_setworks without a restart. When its provider already has it (a slugcomposio_searchjust found), it is callable on the next step of the same turn. Either way the agent reloads once the turn ends, so it is pinned from the next message. Plugin API:ToolContext.pinTools(slugs). - A reload refused before it waited (a file on disk that does not load) now emits
agent.reloadedwithok: false, as a refusal after the wait already did, so a webhook sees every refusal.
Since 0.2.0-pilot.12
- Claude 5.x (Sonnet 5.5, Opus 5.5, Fable 5.1) with thinking: a tool turn no longer fails at its second step with "Invalid signature in thinking block … bound to a different conversation". For a role whose thinking is replayed, the turn's own calls and results now follow its input instead of preceding it, so each step only appends to the last. On Bedrock, a replay that is still refused (a compaction or phase change mid-turn) is sent again once without thinking, and reported as a retry. Other models keep today's order.
- Bedrock: prompt-caching models (Claude, Nova) get a rolling cache point at the end of every request, and their turn's trace follows the input, so each step of a tool loop reads the ea...
v0.2.0-pilot.14
A pre-release for the multiplayer runtime: one silo per user, run by a control plane.
Since 0.2.0-pilot.13
- Bedrock: Nova no longer fails on the second call of a native tool turn with "extraneous key [cachePoint] is not permitted". pilot.13's rolling cache point is left out of a Nova message that carries a tool result; Claude keeps it.
finalTexton a turn's result and onturn.end: the last step's prose alone. The reply still joins every step's, so a lead-in a model repeats before each tool call ("Yes, Outlook. Let me try…") appears once infinalText.- Errors take an optional
detail: a provider's own words, verbatim. Bedrock now puts AWS's text there instead of inmessage, so an access refusal's assumed-role ARN is no longer in what an embedder shows people. A failed turn's record carries it aserrorDetail(store migration 29). channels[].roleruns a channel's turns on a model role declared undermodel:, e.g. WhatsApp on a cheaper model than the web chat. Absent ismain. A role that is not declared refuses the manifest.- The reminder tier now opens with a line saying it is the agent's own instructions and the person did not write it. On Bedrock, any system message after the start of the conversation is sent fenced in
<system>…</system>rather than as bare user text. A model had read an unframed reminder as something the person pasted. - A workspace file that reaches the model with an unrendered
{{vars.…}}placeholder is reported asworkspace_unrendered_var, on the agent's warnings and byvalidate. A placeholder inside an HTML comment, which the model never sees, is not. tools.providers.system.confineReads: trueconfinesfile_read,globandgrepto the agent's directory and itswriteRoots, a symlink pointing out included, so in a silo one agent cannot read another's notes. Off by default;config_setcannot set it;execis not bound by it.skills.trusted: [names]: only these skills' scripts become tools. Any other skill, such as one a person uploaded or a community skill, is still used for its steps, and its scripts are listed as documentation only. Absent, every skill's scripts run, as before.config_setcannot set it.- A tool pinned with
config_setworks without a restart. When its provider already has it (a slugcomposio_searchjust found), it is callable on the next step of the same turn. Either way the agent reloads once the turn ends, so it is pinned from the next message. Plugin API:ToolContext.pinTools(slugs). - A reload refused before it waited (a file on disk that does not load) now emits
agent.reloadedwithok: false, as a refusal after the wait already did, so a webhook sees every refusal.
Since 0.2.0-pilot.12
- Claude 5.x (Sonnet 5.5, Opus 5.5, Fable 5.1) with thinking: a tool turn no longer fails at its second step with "Invalid signature in thinking block … bound to a different conversation". For a role whose thinking is replayed, the turn's own calls and results now follow its input instead of preceding it, so each step only appends to the last. On Bedrock, a replay that is still refused (a compaction or phase change mid-turn) is sent again once without thinking, and reported as a retry. Other models keep today's order.
- Bedrock: prompt-caching models (Claude, Nova) get a rolling cache point at the end of every request, and their turn's trace follows the input, so each step of a tool loop reads the earlier steps from the cache instead of resending them at full price.
limits.noProgress.sameTool: Nends a turn asno_progressafter N calls to one tool, whatever the arguments. Off unless set.- WhatsApp: a 515 "restart required" close reconnects at once, without showing "disconnected" or counting a failure.
- A recalled excerpt of another conversation (
memory.includeHistory) now says it is a different conversation and background only, not a task to continue. A new chat had taken a just-finished chat's task as its own and re-proposed it untilno_progress. - New event
memory.recalledlists the passages a turn's prompt recalled (source,score), so where something in a reply came from shows on the stream. - Bedrock: Amazon Nova's
<thinking>…</thinking>, which it writes into its reply text once it is given tools, is now treated as reasoning: shown and stored as reasoning, never in the reply. A tag split across stream chunks is handled. Other models' text is untouched.
Since 0.2.0-pilot.11
- A tool provider is no longer asked to refresh a pinned slug another provider resolved. Composio fetched
GET /tools/<slug>for every pinned MCP tool on each boot, reload andtools/refresh, and got a 404 each time; it now fetches only slugs nobody resolved, so a cold cache still heals. - A backup's
store.dbno longer carries the serve leases of the process it was taken from. A restore that started within 90 seconds of the backup was refused withagent_already_serving, naming a pid that belonged to something else in the new container.
Since 0.2.0-pilot.10
GET /v1/backup?include=homeadds the rest of the state directory underhome/: stopped agents, templates, and anything an embedder keeps beside the store, such as a team drive and its git directory. It never adds the livestore.db*,logs/or thesources/clone cache..envfiles and the host token are added only withinclude=env, and.gitdirectories only withinclude=git.backup.jsonrecords the directory, and the wire spec's restore steps cover it.- A file that grows or shrinks while a backup is being read no longer corrupts the archive. Its entry holds exactly the size it had when the backup started.
Since 0.2.0-pilot.9
tools.providers.web.baseUrl(the search backend) andtools.providers.web.firecrawl.baseUrl(scrape, crawl, map) point the web provider at a relay with the same paths and bodies, so a platform key need not be in the agent's environment.tool.usageis unchanged.config_setcan no longer set any provider'sbaseUrl, by path or inside atools.providersvalue. Composio's was settable before, which let an agent send its token to an address of its choosing.- An agent asked by another member's agent is now also told that its owner's private notes and memory are not in the turn, and to say it cannot confirm something it cannot check (availability, a preference) rather than guess. Not said when the owner is the one asking.
- Bedrock: a 5xx from the container-credentials endpoint carries the body's own
code(orbedrock_credentials_unavailable) and is retried, instead of reaching the turn asmodel_http_error. POST /v1/agents/:id/sessions/:key/recall {recall: false}takes a conversation out of history recall without deleting it: its passages go at once and stay out.trueputs it back. The session then readsrecall: false; the client'ssetRecallsends it.GET /v1/backup?include=env,gitadds each agent's.envand.git, andbackup.jsonrecords each agent's directory. Restoring is documented in the wire spec: with the server stopped,store.dbto the store path and eachagents/<id>/to its recorded directory.- The wire spec lists what
tool.usage'sunitscounts for each web provider and operation.
Since 0.2.0-pilot.8
tools.providers.system.env: scrub(or a list of names to pass) keeps the runtime's secrets out of whatexecand skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.X_FILEsetsXfrom that file when the CLI starts, unlessXis set already. The value never appears in the process's environment block.AWS_*is left to the SDK.- Bedrock: when
AWS_CONTAINER_CREDENTIALS_FULL_URIis set, the endpoint's own refusal code (for examplecredit_exhausted) is the turn's error code, terminal, instead ofbedrock_credentials_missing. - Firecrawl, first-class:
tools.providers.web.firecrawl: {}routesweb_fetchthrough Firecrawl's scrape (JavaScript pages come back as markdown) and addsweb_crawlandweb_map.backend: firecrawlis a search backend too. - Every web search, scrape, crawl and map emits
tool.usage(provider,unit,units,participant). Any tool can report its spend this way throughToolContext.meter. - An agent asked by another member's agent is told whose agent it is and who is asking. Participants take
titleandtimezone(POST /v1/participants), and both appear in that note. - An MCP server's
turnHeadersends the turn id with every call, and the call id in<turnHeader>-Call. GET /v1/backup(admin, unscoped key) streams the silo as a tar.gz: a consistent store snapshot plus every hosted agent's directory, without.envfiles.GET /v1/agents/:id/assigneereads the assignment back.execno longer says "the requested timeout was longer than allowed" on a call that asked for no timeout. It said so on every such call, because the declared default was clamped.
Since 0.2.0-pilot.7
PATCH /configtakes{path, remove: true}to take a field out of the manifest, so it returns to its default, with the same checks as a set: a required field is refused, and a field that is not there is left alone. The client'sremoveConfig(path)sends it.- Security fixes from development: the code-scanning and Dependabot findings, the websocket's internal errors logging their cause, and a security policy with private reporting.
- Bedrock: GPT-6 models (
openai.gpt-6*, Luna among them) are no longer senttemperatureortopP, which they refuse on every turn. A role that sets either gets amodel_sampling_unsupportedwarning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.
Since 0.2.0-pilot.6
POST /messagestakesrole: run that turn on a model role declared undermodel:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client'ssendtakes it too.- A person a...
v0.2.0-pilot.13
A pre-release for the multiplayer runtime: one silo per user, run by a control plane.
Since 0.2.0-pilot.12
- Claude 5.x (Sonnet 5.5, Opus 5.5, Fable 5.1) with thinking: a tool turn no longer fails at its second step with "Invalid signature in thinking block … bound to a different conversation". For a role whose thinking is replayed, the turn's own calls and results now follow its input instead of preceding it, so each step only appends to the last. On Bedrock, a replay that is still refused (a compaction or phase change mid-turn) is sent again once without thinking, and reported as a retry. Other models keep today's order.
- Bedrock: prompt-caching models (Claude, Nova) get a rolling cache point at the end of every request, and their turn's trace follows the input, so each step of a tool loop reads the earlier steps from the cache instead of resending them at full price.
limits.noProgress.sameTool: Nends a turn asno_progressafter N calls to one tool, whatever the arguments. Off unless set.- WhatsApp: a 515 "restart required" close reconnects at once, without showing "disconnected" or counting a failure.
- A recalled excerpt of another conversation (
memory.includeHistory) now says it is a different conversation and background only, not a task to continue. A new chat had taken a just-finished chat's task as its own and re-proposed it untilno_progress. - New event
memory.recalledlists the passages a turn's prompt recalled (source,score), so where something in a reply came from shows on the stream. - Bedrock: Amazon Nova's
<thinking>…</thinking>, which it writes into its reply text once it is given tools, is now treated as reasoning: shown and stored as reasoning, never in the reply. A tag split across stream chunks is handled. Other models' text is untouched.
Since 0.2.0-pilot.11
- A tool provider is no longer asked to refresh a pinned slug another provider resolved. Composio fetched
GET /tools/<slug>for every pinned MCP tool on each boot, reload andtools/refresh, and got a 404 each time; it now fetches only slugs nobody resolved, so a cold cache still heals. - A backup's
store.dbno longer carries the serve leases of the process it was taken from. A restore that started within 90 seconds of the backup was refused withagent_already_serving, naming a pid that belonged to something else in the new container.
Since 0.2.0-pilot.10
GET /v1/backup?include=homeadds the rest of the state directory underhome/: stopped agents, templates, and anything an embedder keeps beside the store, such as a team drive and its git directory. It never adds the livestore.db*,logs/or thesources/clone cache..envfiles and the host token are added only withinclude=env, and.gitdirectories only withinclude=git.backup.jsonrecords the directory, and the wire spec's restore steps cover it.- A file that grows or shrinks while a backup is being read no longer corrupts the archive. Its entry holds exactly the size it had when the backup started.
Since 0.2.0-pilot.9
tools.providers.web.baseUrl(the search backend) andtools.providers.web.firecrawl.baseUrl(scrape, crawl, map) point the web provider at a relay with the same paths and bodies, so a platform key need not be in the agent's environment.tool.usageis unchanged.config_setcan no longer set any provider'sbaseUrl, by path or inside atools.providersvalue. Composio's was settable before, which let an agent send its token to an address of its choosing.- An agent asked by another member's agent is now also told that its owner's private notes and memory are not in the turn, and to say it cannot confirm something it cannot check (availability, a preference) rather than guess. Not said when the owner is the one asking.
- Bedrock: a 5xx from the container-credentials endpoint carries the body's own
code(orbedrock_credentials_unavailable) and is retried, instead of reaching the turn asmodel_http_error. POST /v1/agents/:id/sessions/:key/recall {recall: false}takes a conversation out of history recall without deleting it: its passages go at once and stay out.trueputs it back. The session then readsrecall: false; the client'ssetRecallsends it.GET /v1/backup?include=env,gitadds each agent's.envand.git, andbackup.jsonrecords each agent's directory. Restoring is documented in the wire spec: with the server stopped,store.dbto the store path and eachagents/<id>/to its recorded directory.- The wire spec lists what
tool.usage'sunitscounts for each web provider and operation.
Since 0.2.0-pilot.8
tools.providers.system.env: scrub(or a list of names to pass) keeps the runtime's secrets out of whatexecand skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.X_FILEsetsXfrom that file when the CLI starts, unlessXis set already. The value never appears in the process's environment block.AWS_*is left to the SDK.- Bedrock: when
AWS_CONTAINER_CREDENTIALS_FULL_URIis set, the endpoint's own refusal code (for examplecredit_exhausted) is the turn's error code, terminal, instead ofbedrock_credentials_missing. - Firecrawl, first-class:
tools.providers.web.firecrawl: {}routesweb_fetchthrough Firecrawl's scrape (JavaScript pages come back as markdown) and addsweb_crawlandweb_map.backend: firecrawlis a search backend too. - Every web search, scrape, crawl and map emits
tool.usage(provider,unit,units,participant). Any tool can report its spend this way throughToolContext.meter. - An agent asked by another member's agent is told whose agent it is and who is asking. Participants take
titleandtimezone(POST /v1/participants), and both appear in that note. - An MCP server's
turnHeadersends the turn id with every call, and the call id in<turnHeader>-Call. GET /v1/backup(admin, unscoped key) streams the silo as a tar.gz: a consistent store snapshot plus every hosted agent's directory, without.envfiles.GET /v1/agents/:id/assigneereads the assignment back.execno longer says "the requested timeout was longer than allowed" on a call that asked for no timeout. It said so on every such call, because the declared default was clamped.
Since 0.2.0-pilot.7
PATCH /configtakes{path, remove: true}to take a field out of the manifest, so it returns to its default, with the same checks as a set: a required field is refused, and a field that is not there is left alone. The client'sremoveConfig(path)sends it.- Security fixes from development: the code-scanning and Dependabot findings, the websocket's internal errors logging their cause, and a security policy with private reporting.
- Bedrock: GPT-6 models (
openai.gpt-6*, Luna among them) are no longer senttemperatureortopP, which they refuse on every turn. A role that sets either gets amodel_sampling_unsupportedwarning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.
Since 0.2.0-pilot.6
POST /messagestakesrole: run that turn on a model role declared undermodel:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client'ssendtakes it too.- A person adds or replaces a named role with
PATCH /config path model.<name>(a map:{id, api or baseUrl, apiKeyEnv, …}). - A turn on any role other than main, a schedule's or a message's, is budgeted against that role's own context window instead of main's.
- Photos sent on Telegram, WhatsApp, Slack and Teams reach the model with the turn, as
POST /messagesimagesdo (at most five, each up to 3.75 MB). On a model that reads no images, the sender is told so. Channel plugins put them onRawInbound.images. - Two members' agents may delegate to each other (
delegation.toboth ways). This was refused at load asteam_cycle. A delegation is one hop: the asked agent cannot hand the work on. - An agent asked by another member's agent reads its owner's shared notes and the space, not its private memory, unless it is working for its own owner. Before, a delegated turn read everything and returned the result to the person who asked.
PATCH /configsetsdelegation.offeranddelegation.to. An offer change reloads the agents that may ask, and each one is reported underpeers.- Under NLT, a tool field that takes a list of objects works: a JSON list kept its objects as
"[object Object]"and was refused, and{…}, {…}or a pretty-printed object was split into fragments. The catalogue now names an object field's own keys instead oflist of objectalone.
Since 0.2.0-pilot.5
- Bedrock: Claude 4.7 and later (Sonnet 5.5, Opus 5.5) take
reasoningEffortas adaptive thinking with an effort instead of the thinking budget they refuse.reasoningEffortgainsxhighandmax.noneis each model's own off switch, or low effort where thinking cannot be turned off, said at load.temperatureandtopPare not sent to models that refuse them.openai.*models get the effort asreasoning: {effort}. gpt-6*resolves to its own capability row (1,050,000 window, 128,000 output, native tools, vision; VelaCrew's figures).- A refused reply (a model's safety classifier, a guardrail, or a chat-completions
content_filterfinish) ends the turn as an error,model_refused, instead of an empty answer. subagents:runs a routed tool call in a throwaway child of the same agent. The parent reads the child's artifact ({summary}by default) instead of the raw output. Routing happens after the policy and the write gate, so a refused call starts no child.- A child inherits its parent's taint, stand-in deferral, acting participant and cancellation, and never spawns one of its own. Its tools must be ones the parent pins.
model.subagent(orsubagents[].model) runs children on a cheaper mo...
v0.2.0-pilot.12
A pre-release for the multiplayer runtime: one silo per user, run by a control plane.
Since 0.2.0-pilot.11
- A tool provider is no longer asked to refresh a pinned slug another provider resolved. Composio fetched
GET /tools/<slug>for every pinned MCP tool on each boot, reload andtools/refresh, and got a 404 each time; it now fetches only slugs nobody resolved, so a cold cache still heals. - A backup's
store.dbno longer carries the serve leases of the process it was taken from. A restore that started within 90 seconds of the backup was refused withagent_already_serving, naming a pid that belonged to something else in the new container.
Since 0.2.0-pilot.10
GET /v1/backup?include=homeadds the rest of the state directory underhome/: stopped agents, templates, and anything an embedder keeps beside the store, such as a team drive and its git directory. It never adds the livestore.db*,logs/or thesources/clone cache..envfiles and the host token are added only withinclude=env, and.gitdirectories only withinclude=git.backup.jsonrecords the directory, and the wire spec's restore steps cover it.- A file that grows or shrinks while a backup is being read no longer corrupts the archive. Its entry holds exactly the size it had when the backup started.
Since 0.2.0-pilot.9
tools.providers.web.baseUrl(the search backend) andtools.providers.web.firecrawl.baseUrl(scrape, crawl, map) point the web provider at a relay with the same paths and bodies, so a platform key need not be in the agent's environment.tool.usageis unchanged.config_setcan no longer set any provider'sbaseUrl, by path or inside atools.providersvalue. Composio's was settable before, which let an agent send its token to an address of its choosing.- An agent asked by another member's agent is now also told that its owner's private notes and memory are not in the turn, and to say it cannot confirm something it cannot check (availability, a preference) rather than guess. Not said when the owner is the one asking.
- Bedrock: a 5xx from the container-credentials endpoint carries the body's own
code(orbedrock_credentials_unavailable) and is retried, instead of reaching the turn asmodel_http_error. POST /v1/agents/:id/sessions/:key/recall {recall: false}takes a conversation out of history recall without deleting it: its passages go at once and stay out.trueputs it back. The session then readsrecall: false; the client'ssetRecallsends it.GET /v1/backup?include=env,gitadds each agent's.envand.git, andbackup.jsonrecords each agent's directory. Restoring is documented in the wire spec: with the server stopped,store.dbto the store path and eachagents/<id>/to its recorded directory.- The wire spec lists what
tool.usage'sunitscounts for each web provider and operation.
Since 0.2.0-pilot.8
tools.providers.system.env: scrub(or a list of names to pass) keeps the runtime's secrets out of whatexecand skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.X_FILEsetsXfrom that file when the CLI starts, unlessXis set already. The value never appears in the process's environment block.AWS_*is left to the SDK.- Bedrock: when
AWS_CONTAINER_CREDENTIALS_FULL_URIis set, the endpoint's own refusal code (for examplecredit_exhausted) is the turn's error code, terminal, instead ofbedrock_credentials_missing. - Firecrawl, first-class:
tools.providers.web.firecrawl: {}routesweb_fetchthrough Firecrawl's scrape (JavaScript pages come back as markdown) and addsweb_crawlandweb_map.backend: firecrawlis a search backend too. - Every web search, scrape, crawl and map emits
tool.usage(provider,unit,units,participant). Any tool can report its spend this way throughToolContext.meter. - An agent asked by another member's agent is told whose agent it is and who is asking. Participants take
titleandtimezone(POST /v1/participants), and both appear in that note. - An MCP server's
turnHeadersends the turn id with every call, and the call id in<turnHeader>-Call. GET /v1/backup(admin, unscoped key) streams the silo as a tar.gz: a consistent store snapshot plus every hosted agent's directory, without.envfiles.GET /v1/agents/:id/assigneereads the assignment back.execno longer says "the requested timeout was longer than allowed" on a call that asked for no timeout. It said so on every such call, because the declared default was clamped.
Since 0.2.0-pilot.7
PATCH /configtakes{path, remove: true}to take a field out of the manifest, so it returns to its default, with the same checks as a set: a required field is refused, and a field that is not there is left alone. The client'sremoveConfig(path)sends it.- Security fixes from development: the code-scanning and Dependabot findings, the websocket's internal errors logging their cause, and a security policy with private reporting.
- Bedrock: GPT-6 models (
openai.gpt-6*, Luna among them) are no longer senttemperatureortopP, which they refuse on every turn. A role that sets either gets amodel_sampling_unsupportedwarning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.
Since 0.2.0-pilot.6
POST /messagestakesrole: run that turn on a model role declared undermodel:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client'ssendtakes it too.- A person adds or replaces a named role with
PATCH /config path model.<name>(a map:{id, api or baseUrl, apiKeyEnv, …}). - A turn on any role other than main, a schedule's or a message's, is budgeted against that role's own context window instead of main's.
- Photos sent on Telegram, WhatsApp, Slack and Teams reach the model with the turn, as
POST /messagesimagesdo (at most five, each up to 3.75 MB). On a model that reads no images, the sender is told so. Channel plugins put them onRawInbound.images. - Two members' agents may delegate to each other (
delegation.toboth ways). This was refused at load asteam_cycle. A delegation is one hop: the asked agent cannot hand the work on. - An agent asked by another member's agent reads its owner's shared notes and the space, not its private memory, unless it is working for its own owner. Before, a delegated turn read everything and returned the result to the person who asked.
PATCH /configsetsdelegation.offeranddelegation.to. An offer change reloads the agents that may ask, and each one is reported underpeers.- Under NLT, a tool field that takes a list of objects works: a JSON list kept its objects as
"[object Object]"and was refused, and{…}, {…}or a pretty-printed object was split into fragments. The catalogue now names an object field's own keys instead oflist of objectalone.
Since 0.2.0-pilot.5
- Bedrock: Claude 4.7 and later (Sonnet 5.5, Opus 5.5) take
reasoningEffortas adaptive thinking with an effort instead of the thinking budget they refuse.reasoningEffortgainsxhighandmax.noneis each model's own off switch, or low effort where thinking cannot be turned off, said at load.temperatureandtopPare not sent to models that refuse them.openai.*models get the effort asreasoning: {effort}. gpt-6*resolves to its own capability row (1,050,000 window, 128,000 output, native tools, vision; VelaCrew's figures).- A refused reply (a model's safety classifier, a guardrail, or a chat-completions
content_filterfinish) ends the turn as an error,model_refused, instead of an empty answer. subagents:runs a routed tool call in a throwaway child of the same agent. The parent reads the child's artifact ({summary}by default) instead of the raw output. Routing happens after the policy and the write gate, so a refused call starts no child.- A child inherits its parent's taint, stand-in deferral, acting participant and cancellation, and never spawns one of its own. Its tools must be ones the parent pins.
model.subagent(orsubagents[].model) runs children on a cheaper model. Their usage rows andmodel.resultevents sayrole: subagent.- A subagent's events carry
parentTurnIdandparentSessionKey, andhandoff.start/handoff.resultgainkind,nameand the parent'scallId. A turn's stream includes its subagents' events withchildren: true(also on the client'sstream()), and still ends on its ownturn.end. A key scoped to a session reaches the subagents that session ran. - The chat shows a routed call's subagent under its tool row: one line (
↳ subagent inbox · 3 steps · 1.2k tokens · ok) that ⌥r opens to the child's calls, in the TUI and as a folded block in the web UI. ⌥r works on a model that streams no reasoning when there is a subagent block to open. - A turn whose own tool result pushed the prompt past compaction's first threshold could lose its whole history mid-turn, repeat the call and end in
no_progress(since 0.1.0). It happened whenever the compaction stages that ran could change nothing, which is the usual case for one large result in the current turn. - A subagent is told what the person asked, ahead of the call it was handed, and reads its call's whole output up to its own window rather than the parent's
observationMaxTokens. submit_artifactmust be the only call in its step (ToolSpec.alone). A subagent or team member that submitted in the same step as its tool call was reporting a result that did not exist yet.- Under the NLT dialect, an unclosed
<invoke name="…">line is treated as an attempted call and asked for again, instead of being shown as the reply. bun run eval:subagentsmeasures routed calls against keeping the work in the parent's context (evals/subagents/).- The web chat shows a quick reply as it arri...
v0.2.0-pilot.9
A pre-release for the multiplayer runtime: one silo per user, run by a control plane.
Since 0.2.0-pilot.8
tools.providers.system.env: scrub(or a list of names to pass) keeps the runtime's secrets out of whatexecand skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.X_FILEsetsXfrom that file when the CLI starts, unlessXis set already. The value never appears in the process's environment block.AWS_*is left to the SDK.- Bedrock: when
AWS_CONTAINER_CREDENTIALS_FULL_URIis set, the endpoint's own refusal code (for examplecredit_exhausted) is the turn's error code, terminal, instead ofbedrock_credentials_missing. - Firecrawl, first-class:
tools.providers.web.firecrawl: {}routesweb_fetchthrough Firecrawl's scrape (JavaScript pages come back as markdown) and addsweb_crawlandweb_map.backend: firecrawlis a search backend too. - Every web search, scrape, crawl and map emits
tool.usage(provider,unit,units,participant). Any tool can report its spend this way throughToolContext.meter. - An agent asked by another member's agent is told whose agent it is and who is asking. Participants take
titleandtimezone(POST /v1/participants), and both appear in that note. - An MCP server's
turnHeadersends the turn id with every call, and the call id in<turnHeader>-Call. GET /v1/backup(admin, unscoped key) streams the silo as a tar.gz: a consistent store snapshot plus every hosted agent's directory, without.envfiles.GET /v1/agents/:id/assigneereads the assignment back.execno longer says "the requested timeout was longer than allowed" on a call that asked for no timeout. It said so on every such call, because the declared default was clamped.
Since 0.2.0-pilot.7
PATCH /configtakes{path, remove: true}to take a field out of the manifest, so it returns to its default, with the same checks as a set: a required field is refused, and a field that is not there is left alone. The client'sremoveConfig(path)sends it.- Security fixes from development: the code-scanning and Dependabot findings, the websocket's internal errors logging their cause, and a security policy with private reporting.
- Bedrock: GPT-6 models (
openai.gpt-6*, Luna among them) are no longer senttemperatureortopP, which they refuse on every turn. A role that sets either gets amodel_sampling_unsupportedwarning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.
Since 0.2.0-pilot.6
POST /messagestakesrole: run that turn on a model role declared undermodel:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client'ssendtakes it too.- A person adds or replaces a named role with
PATCH /config path model.<name>(a map:{id, api or baseUrl, apiKeyEnv, …}). - A turn on any role other than main, a schedule's or a message's, is budgeted against that role's own context window instead of main's.
- Photos sent on Telegram, WhatsApp, Slack and Teams reach the model with the turn, as
POST /messagesimagesdo (at most five, each up to 3.75 MB). On a model that reads no images, the sender is told so. Channel plugins put them onRawInbound.images. - Two members' agents may delegate to each other (
delegation.toboth ways). This was refused at load asteam_cycle. A delegation is one hop: the asked agent cannot hand the work on. - An agent asked by another member's agent reads its owner's shared notes and the space, not its private memory, unless it is working for its own owner. Before, a delegated turn read everything and returned the result to the person who asked.
PATCH /configsetsdelegation.offeranddelegation.to. An offer change reloads the agents that may ask, and each one is reported underpeers.- Under NLT, a tool field that takes a list of objects works: a JSON list kept its objects as
"[object Object]"and was refused, and{…}, {…}or a pretty-printed object was split into fragments. The catalogue now names an object field's own keys instead oflist of objectalone.
Since 0.2.0-pilot.5
- Bedrock: Claude 4.7 and later (Sonnet 5.5, Opus 5.5) take
reasoningEffortas adaptive thinking with an effort instead of the thinking budget they refuse.reasoningEffortgainsxhighandmax.noneis each model's own off switch, or low effort where thinking cannot be turned off, said at load.temperatureandtopPare not sent to models that refuse them.openai.*models get the effort asreasoning: {effort}. gpt-6*resolves to its own capability row (1,050,000 window, 128,000 output, native tools, vision; VelaCrew's figures).- A refused reply (a model's safety classifier, a guardrail, or a chat-completions
content_filterfinish) ends the turn as an error,model_refused, instead of an empty answer. subagents:runs a routed tool call in a throwaway child of the same agent. The parent reads the child's artifact ({summary}by default) instead of the raw output. Routing happens after the policy and the write gate, so a refused call starts no child.- A child inherits its parent's taint, stand-in deferral, acting participant and cancellation, and never spawns one of its own. Its tools must be ones the parent pins.
model.subagent(orsubagents[].model) runs children on a cheaper model. Their usage rows andmodel.resultevents sayrole: subagent.- A subagent's events carry
parentTurnIdandparentSessionKey, andhandoff.start/handoff.resultgainkind,nameand the parent'scallId. A turn's stream includes its subagents' events withchildren: true(also on the client'sstream()), and still ends on its ownturn.end. A key scoped to a session reaches the subagents that session ran. - The chat shows a routed call's subagent under its tool row: one line (
↳ subagent inbox · 3 steps · 1.2k tokens · ok) that ⌥r opens to the child's calls, in the TUI and as a folded block in the web UI. ⌥r works on a model that streams no reasoning when there is a subagent block to open. - A turn whose own tool result pushed the prompt past compaction's first threshold could lose its whole history mid-turn, repeat the call and end in
no_progress(since 0.1.0). It happened whenever the compaction stages that ran could change nothing, which is the usual case for one large result in the current turn. - A subagent is told what the person asked, ahead of the call it was handed, and reads its call's whole output up to its own window rather than the parent's
observationMaxTokens. submit_artifactmust be the only call in its step (ToolSpec.alone). A subagent or team member that submitted in the same step as its tool call was reporting a result that did not exist yet.- Under the NLT dialect, an unclosed
<invoke name="…">line is treated as an attempted call and asked for again, instead of being shown as the reply. bun run eval:subagentsmeasures routed calls against keeping the work in the parent's context (evals/subagents/).- The web chat shows a quick reply as it arrives. A reply whose tokens finished before the page attached to the turn was missing from the replay, so the page drew no reply until a reload. The client's
sendtakeschunks: trueto record a turn's tokens from its first one, and the web sends with it. - Conversation lists (the web sidebar, the TUI's session picker,
run --continue) leave out the sessions a subagent or a team handoff ran in. The API still lists them. run --continueand a barerun --sessionno longer fail with "Cannot access 'source' before initialization" when no host is running (broken since 0.1.0).- Bedrock: a tool turn in a fresh session no longer fails on its second step with "A conversation must start with a user message" (Nova Micro under the NLT dialect). The turn's input is sent first whenever the request would otherwise open with the model's own call, under both dialects.
run --plainprints only its own conversation's events, so a subagent's reply no longer appears inside the parent's.- The release image builds its tarball once, natively, instead of once per platform under emulation.
Since 0.2.0-pilot.4
- A tool result cut to fit
observationMaxTokensis stored whole, and its marker names the id to read it withartifact_read. Reading an untrusted result back is untrusted too, so it no longer reopens the write gate. GET /v1/agents/:idanswers a stopped agent with the listing'sstatus: "disabled"row instead of 404. Routes that act on it are still 404.- The
workspace_rule_budgetrefusal names the lines it counted and their files.context.rules.onExceedis settable throughPATCH /config(by a person), so a misread line no longer holds every reload. - Under
tools.dialect: nativea skill script (skill.pdf.extract) is sent asskill__pdf__extractinstead of failing the turn that activates it. - Nova Micro, Lite and Pro resolve to their own capability rows (window, output, tools) instead of the 8,192-token fallback.
- A release run from a branch says it built and pushed nothing, and tags its build with the version.
POST /messagestakesimages: a path inside the agent's directory (or inline base64), PNG, JPEG, GIF or WebP. The model sees them on that turn through Bedrock or an OpenAI-compatible endpoint; history keeps[image: <path>]. A model without vision refuses withmodel_no_vision, andcapabilities.visioncan say otherwise. The client'ssendtakesimagestoo.- A schedule takes
tools.allow(the phase grammar),timeoutMsandmaxSteps, in the manifest and over the API. They only narrow the agent's own tools andlimits; an allow entry naming nothing isschedule_tool_unknown.POST …/schedules/:sid/runruns with the same limits as a timed fire. POST /messagestakesruntimeNote: your application's note about the message (...
v0.2.0-pilot.11
A pre-release for the multiplayer runtime: one silo per user, run by a control plane.
Since 0.2.0-pilot.10
GET /v1/backup?include=homeadds the rest of the state directory underhome/: stopped agents, templates, and anything an embedder keeps beside the store, such as a team drive and its git directory. It never adds the livestore.db*,logs/or thesources/clone cache..envfiles and the host token are added only withinclude=env, and.gitdirectories only withinclude=git.backup.jsonrecords the directory, and the wire spec's restore steps cover it.- A file that grows or shrinks while a backup is being read no longer corrupts the archive. Its entry holds exactly the size it had when the backup started.
Since 0.2.0-pilot.9
tools.providers.web.baseUrl(the search backend) andtools.providers.web.firecrawl.baseUrl(scrape, crawl, map) point the web provider at a relay with the same paths and bodies, so a platform key need not be in the agent's environment.tool.usageis unchanged.config_setcan no longer set any provider'sbaseUrl, by path or inside atools.providersvalue. Composio's was settable before, which let an agent send its token to an address of its choosing.- An agent asked by another member's agent is now also told that its owner's private notes and memory are not in the turn, and to say it cannot confirm something it cannot check (availability, a preference) rather than guess. Not said when the owner is the one asking.
- Bedrock: a 5xx from the container-credentials endpoint carries the body's own
code(orbedrock_credentials_unavailable) and is retried, instead of reaching the turn asmodel_http_error. POST /v1/agents/:id/sessions/:key/recall {recall: false}takes a conversation out of history recall without deleting it: its passages go at once and stay out.trueputs it back. The session then readsrecall: false; the client'ssetRecallsends it.GET /v1/backup?include=env,gitadds each agent's.envand.git, andbackup.jsonrecords each agent's directory. Restoring is documented in the wire spec: with the server stopped,store.dbto the store path and eachagents/<id>/to its recorded directory.- The wire spec lists what
tool.usage'sunitscounts for each web provider and operation.
Since 0.2.0-pilot.8
tools.providers.system.env: scrub(or a list of names to pass) keeps the runtime's secrets out of whatexecand skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.X_FILEsetsXfrom that file when the CLI starts, unlessXis set already. The value never appears in the process's environment block.AWS_*is left to the SDK.- Bedrock: when
AWS_CONTAINER_CREDENTIALS_FULL_URIis set, the endpoint's own refusal code (for examplecredit_exhausted) is the turn's error code, terminal, instead ofbedrock_credentials_missing. - Firecrawl, first-class:
tools.providers.web.firecrawl: {}routesweb_fetchthrough Firecrawl's scrape (JavaScript pages come back as markdown) and addsweb_crawlandweb_map.backend: firecrawlis a search backend too. - Every web search, scrape, crawl and map emits
tool.usage(provider,unit,units,participant). Any tool can report its spend this way throughToolContext.meter. - An agent asked by another member's agent is told whose agent it is and who is asking. Participants take
titleandtimezone(POST /v1/participants), and both appear in that note. - An MCP server's
turnHeadersends the turn id with every call, and the call id in<turnHeader>-Call. GET /v1/backup(admin, unscoped key) streams the silo as a tar.gz: a consistent store snapshot plus every hosted agent's directory, without.envfiles.GET /v1/agents/:id/assigneereads the assignment back.execno longer says "the requested timeout was longer than allowed" on a call that asked for no timeout. It said so on every such call, because the declared default was clamped.
Since 0.2.0-pilot.7
PATCH /configtakes{path, remove: true}to take a field out of the manifest, so it returns to its default, with the same checks as a set: a required field is refused, and a field that is not there is left alone. The client'sremoveConfig(path)sends it.- Security fixes from development: the code-scanning and Dependabot findings, the websocket's internal errors logging their cause, and a security policy with private reporting.
- Bedrock: GPT-6 models (
openai.gpt-6*, Luna among them) are no longer senttemperatureortopP, which they refuse on every turn. A role that sets either gets amodel_sampling_unsupportedwarning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.
Since 0.2.0-pilot.6
POST /messagestakesrole: run that turn on a model role declared undermodel:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client'ssendtakes it too.- A person adds or replaces a named role with
PATCH /config path model.<name>(a map:{id, api or baseUrl, apiKeyEnv, …}). - A turn on any role other than main, a schedule's or a message's, is budgeted against that role's own context window instead of main's.
- Photos sent on Telegram, WhatsApp, Slack and Teams reach the model with the turn, as
POST /messagesimagesdo (at most five, each up to 3.75 MB). On a model that reads no images, the sender is told so. Channel plugins put them onRawInbound.images. - Two members' agents may delegate to each other (
delegation.toboth ways). This was refused at load asteam_cycle. A delegation is one hop: the asked agent cannot hand the work on. - An agent asked by another member's agent reads its owner's shared notes and the space, not its private memory, unless it is working for its own owner. Before, a delegated turn read everything and returned the result to the person who asked.
PATCH /configsetsdelegation.offeranddelegation.to. An offer change reloads the agents that may ask, and each one is reported underpeers.- Under NLT, a tool field that takes a list of objects works: a JSON list kept its objects as
"[object Object]"and was refused, and{…}, {…}or a pretty-printed object was split into fragments. The catalogue now names an object field's own keys instead oflist of objectalone.
Since 0.2.0-pilot.5
- Bedrock: Claude 4.7 and later (Sonnet 5.5, Opus 5.5) take
reasoningEffortas adaptive thinking with an effort instead of the thinking budget they refuse.reasoningEffortgainsxhighandmax.noneis each model's own off switch, or low effort where thinking cannot be turned off, said at load.temperatureandtopPare not sent to models that refuse them.openai.*models get the effort asreasoning: {effort}. gpt-6*resolves to its own capability row (1,050,000 window, 128,000 output, native tools, vision; VelaCrew's figures).- A refused reply (a model's safety classifier, a guardrail, or a chat-completions
content_filterfinish) ends the turn as an error,model_refused, instead of an empty answer. subagents:runs a routed tool call in a throwaway child of the same agent. The parent reads the child's artifact ({summary}by default) instead of the raw output. Routing happens after the policy and the write gate, so a refused call starts no child.- A child inherits its parent's taint, stand-in deferral, acting participant and cancellation, and never spawns one of its own. Its tools must be ones the parent pins.
model.subagent(orsubagents[].model) runs children on a cheaper model. Their usage rows andmodel.resultevents sayrole: subagent.- A subagent's events carry
parentTurnIdandparentSessionKey, andhandoff.start/handoff.resultgainkind,nameand the parent'scallId. A turn's stream includes its subagents' events withchildren: true(also on the client'sstream()), and still ends on its ownturn.end. A key scoped to a session reaches the subagents that session ran. - The chat shows a routed call's subagent under its tool row: one line (
↳ subagent inbox · 3 steps · 1.2k tokens · ok) that ⌥r opens to the child's calls, in the TUI and as a folded block in the web UI. ⌥r works on a model that streams no reasoning when there is a subagent block to open. - A turn whose own tool result pushed the prompt past compaction's first threshold could lose its whole history mid-turn, repeat the call and end in
no_progress(since 0.1.0). It happened whenever the compaction stages that ran could change nothing, which is the usual case for one large result in the current turn. - A subagent is told what the person asked, ahead of the call it was handed, and reads its call's whole output up to its own window rather than the parent's
observationMaxTokens. submit_artifactmust be the only call in its step (ToolSpec.alone). A subagent or team member that submitted in the same step as its tool call was reporting a result that did not exist yet.- Under the NLT dialect, an unclosed
<invoke name="…">line is treated as an attempted call and asked for again, instead of being shown as the reply. bun run eval:subagentsmeasures routed calls against keeping the work in the parent's context (evals/subagents/).- The web chat shows a quick reply as it arrives. A reply whose tokens finished before the page attached to the turn was missing from the replay, so the page drew no reply until a reload. The client's
sendtakeschunks: trueto record a turn's tokens from its first one, and the web sends with it. - Conversation lists (the web sidebar, the TUI's session picker,
run --continue) leave out the sessions a subagent or a team handoff ran in. The API still lists them. run --continueand a barerun --sessionno longer fail with "Cannot access 'source' before initialization" when no host is running (broken sinc...
v0.2.0-pilot.10
A pre-release for the multiplayer runtime: one silo per user, run by a control plane.
Since 0.2.0-pilot.9
tools.providers.web.baseUrl(the search backend) andtools.providers.web.firecrawl.baseUrl(scrape, crawl, map) point the web provider at a relay with the same paths and bodies, so a platform key need not be in the agent's environment.tool.usageis unchanged.config_setcan no longer set any provider'sbaseUrl, by path or inside atools.providersvalue. Composio's was settable before, which let an agent send its token to an address of its choosing.- An agent asked by another member's agent is now also told that its owner's private notes and memory are not in the turn, and to say it cannot confirm something it cannot check (availability, a preference) rather than guess. Not said when the owner is the one asking.
- Bedrock: a 5xx from the container-credentials endpoint carries the body's own
code(orbedrock_credentials_unavailable) and is retried, instead of reaching the turn asmodel_http_error. POST /v1/agents/:id/sessions/:key/recall {recall: false}takes a conversation out of history recall without deleting it: its passages go at once and stay out.trueputs it back. The session then readsrecall: false; the client'ssetRecallsends it.GET /v1/backup?include=env,gitadds each agent's.envand.git, andbackup.jsonrecords each agent's directory. Restoring is documented in the wire spec: with the server stopped,store.dbto the store path and eachagents/<id>/to its recorded directory.- The wire spec lists what
tool.usage'sunitscounts for each web provider and operation.
Since 0.2.0-pilot.8
tools.providers.system.env: scrub(or a list of names to pass) keeps the runtime's secrets out of whatexecand skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.X_FILEsetsXfrom that file when the CLI starts, unlessXis set already. The value never appears in the process's environment block.AWS_*is left to the SDK.- Bedrock: when
AWS_CONTAINER_CREDENTIALS_FULL_URIis set, the endpoint's own refusal code (for examplecredit_exhausted) is the turn's error code, terminal, instead ofbedrock_credentials_missing. - Firecrawl, first-class:
tools.providers.web.firecrawl: {}routesweb_fetchthrough Firecrawl's scrape (JavaScript pages come back as markdown) and addsweb_crawlandweb_map.backend: firecrawlis a search backend too. - Every web search, scrape, crawl and map emits
tool.usage(provider,unit,units,participant). Any tool can report its spend this way throughToolContext.meter. - An agent asked by another member's agent is told whose agent it is and who is asking. Participants take
titleandtimezone(POST /v1/participants), and both appear in that note. - An MCP server's
turnHeadersends the turn id with every call, and the call id in<turnHeader>-Call. GET /v1/backup(admin, unscoped key) streams the silo as a tar.gz: a consistent store snapshot plus every hosted agent's directory, without.envfiles.GET /v1/agents/:id/assigneereads the assignment back.execno longer says "the requested timeout was longer than allowed" on a call that asked for no timeout. It said so on every such call, because the declared default was clamped.
Since 0.2.0-pilot.7
PATCH /configtakes{path, remove: true}to take a field out of the manifest, so it returns to its default, with the same checks as a set: a required field is refused, and a field that is not there is left alone. The client'sremoveConfig(path)sends it.- Security fixes from development: the code-scanning and Dependabot findings, the websocket's internal errors logging their cause, and a security policy with private reporting.
- Bedrock: GPT-6 models (
openai.gpt-6*, Luna among them) are no longer senttemperatureortopP, which they refuse on every turn. A role that sets either gets amodel_sampling_unsupportedwarning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.
Since 0.2.0-pilot.6
POST /messagestakesrole: run that turn on a model role declared undermodel:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client'ssendtakes it too.- A person adds or replaces a named role with
PATCH /config path model.<name>(a map:{id, api or baseUrl, apiKeyEnv, …}). - A turn on any role other than main, a schedule's or a message's, is budgeted against that role's own context window instead of main's.
- Photos sent on Telegram, WhatsApp, Slack and Teams reach the model with the turn, as
POST /messagesimagesdo (at most five, each up to 3.75 MB). On a model that reads no images, the sender is told so. Channel plugins put them onRawInbound.images. - Two members' agents may delegate to each other (
delegation.toboth ways). This was refused at load asteam_cycle. A delegation is one hop: the asked agent cannot hand the work on. - An agent asked by another member's agent reads its owner's shared notes and the space, not its private memory, unless it is working for its own owner. Before, a delegated turn read everything and returned the result to the person who asked.
PATCH /configsetsdelegation.offeranddelegation.to. An offer change reloads the agents that may ask, and each one is reported underpeers.- Under NLT, a tool field that takes a list of objects works: a JSON list kept its objects as
"[object Object]"and was refused, and{…}, {…}or a pretty-printed object was split into fragments. The catalogue now names an object field's own keys instead oflist of objectalone.
Since 0.2.0-pilot.5
- Bedrock: Claude 4.7 and later (Sonnet 5.5, Opus 5.5) take
reasoningEffortas adaptive thinking with an effort instead of the thinking budget they refuse.reasoningEffortgainsxhighandmax.noneis each model's own off switch, or low effort where thinking cannot be turned off, said at load.temperatureandtopPare not sent to models that refuse them.openai.*models get the effort asreasoning: {effort}. gpt-6*resolves to its own capability row (1,050,000 window, 128,000 output, native tools, vision; VelaCrew's figures).- A refused reply (a model's safety classifier, a guardrail, or a chat-completions
content_filterfinish) ends the turn as an error,model_refused, instead of an empty answer. subagents:runs a routed tool call in a throwaway child of the same agent. The parent reads the child's artifact ({summary}by default) instead of the raw output. Routing happens after the policy and the write gate, so a refused call starts no child.- A child inherits its parent's taint, stand-in deferral, acting participant and cancellation, and never spawns one of its own. Its tools must be ones the parent pins.
model.subagent(orsubagents[].model) runs children on a cheaper model. Their usage rows andmodel.resultevents sayrole: subagent.- A subagent's events carry
parentTurnIdandparentSessionKey, andhandoff.start/handoff.resultgainkind,nameand the parent'scallId. A turn's stream includes its subagents' events withchildren: true(also on the client'sstream()), and still ends on its ownturn.end. A key scoped to a session reaches the subagents that session ran. - The chat shows a routed call's subagent under its tool row: one line (
↳ subagent inbox · 3 steps · 1.2k tokens · ok) that ⌥r opens to the child's calls, in the TUI and as a folded block in the web UI. ⌥r works on a model that streams no reasoning when there is a subagent block to open. - A turn whose own tool result pushed the prompt past compaction's first threshold could lose its whole history mid-turn, repeat the call and end in
no_progress(since 0.1.0). It happened whenever the compaction stages that ran could change nothing, which is the usual case for one large result in the current turn. - A subagent is told what the person asked, ahead of the call it was handed, and reads its call's whole output up to its own window rather than the parent's
observationMaxTokens. submit_artifactmust be the only call in its step (ToolSpec.alone). A subagent or team member that submitted in the same step as its tool call was reporting a result that did not exist yet.- Under the NLT dialect, an unclosed
<invoke name="…">line is treated as an attempted call and asked for again, instead of being shown as the reply. bun run eval:subagentsmeasures routed calls against keeping the work in the parent's context (evals/subagents/).- The web chat shows a quick reply as it arrives. A reply whose tokens finished before the page attached to the turn was missing from the replay, so the page drew no reply until a reload. The client's
sendtakeschunks: trueto record a turn's tokens from its first one, and the web sends with it. - Conversation lists (the web sidebar, the TUI's session picker,
run --continue) leave out the sessions a subagent or a team handoff ran in. The API still lists them. run --continueand a barerun --sessionno longer fail with "Cannot access 'source' before initialization" when no host is running (broken since 0.1.0).- Bedrock: a tool turn in a fresh session no longer fails on its second step with "A conversation must start with a user message" (Nova Micro under the NLT dialect). The turn's input is sent first whenever the request would otherwise open with the model's own call, under both dialects.
run --plainprints only its own conversation's events, so a subagent's reply no longer appears inside the parent's.- The release image builds its tarball once, natively, instead of once per platform under emulation.
Since 0.2.0-pilot.4
- A tool result cut to fit
observationMaxTokensis stored whole, and its marker names the id to read it with `art...