Skip to content

Releases: moeen-mahmud/dispach

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 08:31
2bfa11e
  • 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.1 is refused at boot with plugin_api_mismatch.
  • Breaking: a reload during a turn answers 202 pending instead of 409, and the turn finishes on the old settings.
  • Breaking: GET /v1/agents/:id on a stopped agent returns its status: "disabled" row instead of 404. Routes that act on it are still 404.
  • Breaking: a scheduled run ending timeout, max_steps, no_progress or error is recorded as an error, not ok.
  • An agent id may no longer start with ~.
  • Store migrations 18–31 run on first boot, with no down-migration. Back up store.db first.
  • 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.yaml has 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 init uses dialect: native where the model calls tools natively. An existing manifest keeps its dialect, and the schema default is still nlt.

Models

  • model.<role>.api selects a transport (default chat-completions); defineModelTransport registers one from a plugin. baseUrl is 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. reasoningEffort gains xhigh and max.
  • images on POST /messages, and photos sent on channels, reach a model with vision. A model without it refuses with model_no_vision.
  • A refused reply (a safety classifier, a guardrail, a content_filter finish) ends the turn as model_refused instead 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 probe settles 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_control markers over chat-completions.
  • Capability rows for GLM 5.3 and hosted qwen/qwen3.5* (262,144 tokens; local qwen3.5* keeps 32,768).

Tools

  • MCP: tools.providers.mcp serves 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.subagent runs children on a cheaper model.
  • A tool pinned with config_set works 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 observationMaxTokens is stored whole and readable with artifact_read.
  • limits.noProgress.sameTool: N ends a turn after N calls to one tool, whatever the arguments.
  • tools.eventDetail: redacted adds a call's arguments and the start of its output to tool events, with secrets replaced.
  • POST /v1/agents/:id/tools/refresh fetches catalogues now and reloads only if something changed.
  • Web: tools.providers.web.baseUrl points the search backend at a relay. Every search emits tool.usage, and any tool can report spend through ToolContext.meter.
  • A built-in pinned again under an MCP namespace (<server>__now) leaves the catalogue, with tool_builtin_shadowed naming 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.identicalCalls lets 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_read and grep never read a secret: .env and key files, credential directories, a process's environ, symlinks included.
  • A path rule in tools.policy matches the normalised path, so workspace/../.env no longer walks past deny: ["file_read(.env)"].
  • tools.providers.system.env: scrub keeps the runtime's secrets out of what exec and skill scripts see. Off by default.
  • tools.providers.system.confineReads: true confines 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_FILE sets X from a file when the CLI starts, so the value never enters the process environment.
  • The agent's config_set cannot set any provider's baseUrl, env, confineReads or personal flag, nor skills.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, /stream and /stop by 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/usage and GET /v1/agents/:id/turns. A call has an id a biller can debit on.
  • Outbound webhooks, signed with Standard Webhooks: /v1/webhooks.
  • limits.maxConcurrentTurns and limits.tokens refuse a turn with 429; GET /v1/activity reports idleness and the next schedule.
  • PATCH /config removes a field ({path, remove: true}), applies a batch in one write (changes[]), and writes nothing for a value already there (changed: false).
  • POST /messages takes role and runtimeNote, your application's note about the message, shown to the model as not the person's.
  • POST /v1/agents/:id/deliveries sends 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/backup streams the silo as a tar.gz. include=home,env,git widen it, and restoring is documented in the wire spec.
  • A turn's result and turn.end carry finalText, the last step's prose. delivery.reply: final sends only that to a channel. Errors carry an optional detail, the provider's own words.
  • dispach/client and dispach/wire ship self-contained type declarations. ink and react are optional, so a client-only install carries no terminal UI.

Memory and context

  • A note saved with memory_write, or an edit to MEMORY.md/USER.md, reaches every session on the next turn. It used to wait for a restart.
  • memory_forget lists 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.recalled lists what a prompt recalled.
  • context.modelIdentity: hidden keeps the model, endpoint and key variable out of the agent's prompt and config_read.
  • A workspace file reaching the model with an unrendered {{vars.…}} is warned about (workspace_unrendered_var).

Operating

  • Kubernetes: docs/17-KUBERNETES.md and examples/kubernetes/silo.yaml. The store refuses to open on NFS or EFS, and DISPACH_DRAIN_MS lets 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, stop and start no longer get a 401 for every agent but the first.
  • serve lists 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: native where the registry knows the model calls tools natively, nlt otherwise.
  • Asks the endpoint for its context window when someone is at the keyboard, or with --measure-window, and writes it to context.window. --yes and 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...

Read more

v0.2.0-pilot.17

v0.2.0-pilot.17 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 12 Oct 10:26

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 a ValidationException on 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_unsupported with 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 optional ToolProvider.refused(). composio_search marks such a tool n/a with the same reason, so the agent does not pin it.
  • Unions of plain values in a tool schema (anyOf/oneOf of string, number, integer and boolean, or a type list) are accepted: the native dialect sends type: [...], 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, not and $ref are still refused.
  • PATCH /config sets model.main as a whole role (transport, id, endpoint, key variable, capabilities) in one write and one reload, person-only; GET /config reports it, baseUrl and the apiKeyEnv name 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/config with a value already in the file writes nothing and does not reload the agent; the reply says changed: false, reloaded: false. A configuration applied in full on every sync no longer reloads the agent once per setting.
  • PATCH /config takes {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 has setConfigs(changes), and setConfig's result now carries changed and reloaded.
  • Removing a block's last key removes the block, so removing limits.noProgress.sameTool no longer leaves an empty noProgress: that would not load.
  • limits.noProgress and limits.noProgress.sameTool are settable by a person through PATCH /config and the config command. config_set cannot 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 is aws (Amazon Polly: options {region, voiceId, engine}; needs polly:SynthesizeSpeech) or openai (/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 emits media.result {kind: "speech", characters}.
  • Amazon Transcribe voice notes in formats other than Ogg/Opus and FLAC (Slack WebM, Teams M4A, MP3) are decoded with ffmpeg first. They were refused before. The image now includes ffmpeg.
  • turn.start carries inputKind: "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, or SOUL.md:). The configuration block gains a context files row naming the files, and config_read's summary lists context.soul.file, context.static, context.volatile and context.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 until no_progress. The first turn after upgrading misses the prompt cache once, because the cached prefix changed.
  • subagents is settable as a whole list by a person or embedder through PATCH /config and changes[], checked as at load (subagent_tool_not_pinned and the rest). The agent's config_set cannot set it. Any edit that unpins a slug a child uses is now refused instead of breaking the next boot.
  • subagents[].timeoutMs bounds a child's routed calls instead of limits.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 until no_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 as tool_personal, with a tool.gated event. PUT /v1/agents/:id/assignee takes channelIds, 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/:id says failed with the load error, or not_running. GET/PATCH /config and PATCH /vars edit its files, answering applied: false until POST /start. The new PUT /v1/agents/:id/workspace/:file replaces 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:4000 endpoint 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 (default shown): the agent's prompt and config_read no 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 whose memory_write saved 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. Emits memory.forgotten {scope, count, messages?}. init pins it; it is not added to policy.allow.
  • A turn records the participant it was taken for (turns.participant_id, migration 31).
  • To stop an earlier conversation from being recalled (includeHistory), use POST /v1/agents/:id/sessions/:key/recall {"recall": false}, which keeps the history (pilot.10), or DELETE /v1/agents/:id/sessions/:key, which removes it and its index entries. A note saved in MEMORY.md is 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.
  • finalText on a turn's result and on turn.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 in finalText.
  • delivery.reply: final (settable with PATCH /config and by the agent's config_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 in message, so an access refusal's assumed-role ARN is no longer in what an embedder shows people. A failed turn's record carries it as errorDetail (store migration 29).
  • channels[].role runs a channel's turns on a model role declared under model:, e.g. WhatsApp on a cheaper model than the web chat. Absent is main. 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 as workspace_unrendered_var, on the agent's warnings and by validate. A placeholder inside an HTML comment, which the model never sees, is not.
  • tools.providers.system.confineReads: true confines file_read, glob and grep to the agent's directory and its writeRoots, a symlink pointing out included, so in a silo one agent cannot read another's notes. Off by default; config_set cannot set it; exec is not bound by it.
  • skills.trusted: [names]: only these skills' scripts become too...
Read more

v0.2.0-pilot.16

v0.2.0-pilot.16 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 09 Oct 10:56

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_unsupported with 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 optional ToolProvider.refused(). composio_search marks such a tool n/a with the same reason, so the agent does not pin it.
  • Unions of plain values in a tool schema (anyOf/oneOf of string, number, integer and boolean, or a type list) are accepted: the native dialect sends type: [...], 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, not and $ref are still refused.
  • PATCH /config sets model.main as a whole role (transport, id, endpoint, key variable, capabilities) in one write and one reload, person-only; GET /config reports it, baseUrl and the apiKeyEnv name 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/config with a value already in the file writes nothing and does not reload the agent; the reply says changed: false, reloaded: false. A configuration applied in full on every sync no longer reloads the agent once per setting.
  • PATCH /config takes {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 has setConfigs(changes), and setConfig's result now carries changed and reloaded.
  • Removing a block's last key removes the block, so removing limits.noProgress.sameTool no longer leaves an empty noProgress: that would not load.
  • limits.noProgress and limits.noProgress.sameTool are settable by a person through PATCH /config and the config command. config_set cannot 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 is aws (Amazon Polly: options {region, voiceId, engine}; needs polly:SynthesizeSpeech) or openai (/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 emits media.result {kind: "speech", characters}.
  • Amazon Transcribe voice notes in formats other than Ogg/Opus and FLAC (Slack WebM, Teams M4A, MP3) are decoded with ffmpeg first. They were refused before. The image now includes ffmpeg.
  • turn.start carries inputKind: "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, or SOUL.md:). The configuration block gains a context files row naming the files, and config_read's summary lists context.soul.file, context.static, context.volatile and context.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 until no_progress. The first turn after upgrading misses the prompt cache once, because the cached prefix changed.
  • subagents is settable as a whole list by a person or embedder through PATCH /config and changes[], checked as at load (subagent_tool_not_pinned and the rest). The agent's config_set cannot set it. Any edit that unpins a slug a child uses is now refused instead of breaking the next boot.
  • subagents[].timeoutMs bounds a child's routed calls instead of limits.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 until no_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 as tool_personal, with a tool.gated event. PUT /v1/agents/:id/assignee takes channelIds, 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/:id says failed with the load error, or not_running. GET/PATCH /config and PATCH /vars edit its files, answering applied: false until POST /start. The new PUT /v1/agents/:id/workspace/:file replaces 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:4000 endpoint 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 (default shown): the agent's prompt and config_read no 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 whose memory_write saved 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. Emits memory.forgotten {scope, count, messages?}. init pins it; it is not added to policy.allow.
  • A turn records the participant it was taken for (turns.participant_id, migration 31).
  • To stop an earlier conversation from being recalled (includeHistory), use POST /v1/agents/:id/sessions/:key/recall {"recall": false}, which keeps the history (pilot.10), or DELETE /v1/agents/:id/sessions/:key, which removes it and its index entries. A note saved in MEMORY.md is 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.
  • finalText on a turn's result and on turn.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 in finalText.
  • delivery.reply: final (settable with PATCH /config and by the agent's config_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 in message, so an access refusal's assumed-role ARN is no longer in what an embedder shows people. A failed turn's record carries it as errorDetail (store migration 29).
  • channels[].role runs a channel's turns on a model role declared under model:, e.g. WhatsApp on a cheaper model than the web chat. Absent is main. 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 as workspace_unrendered_var, on the agent's warnings and by validate. A placeholder inside an HTML comment, which the model never sees, is not.
  • tools.providers.system.confineReads: true confines file_read, glob and grep to the agent's directory and its writeRoots, a symlink pointing out included, so in a silo one agent cannot read another's notes. Off by default; config_set cannot set it; exec is not bound by it.
  • skills.trusted: [names]: only these skills' scripts become tools, and GET /v1/agents/:id/skills marks each skill trusted. 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_set cannot set it.
  • A tool pinned with config_set works without a ...
Read more

v0.2.0-pilot.15

v0.2.0-pilot.15 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 08 Oct 15:35

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/config with a value already in the file writes nothing and does not reload the agent; the reply says changed: false, reloaded: false. A configuration applied in full on every sync no longer reloads the agent once per setting.
  • PATCH /config takes {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 has setConfigs(changes), and setConfig's result now carries changed and reloaded.
  • Removing a block's last key removes the block, so removing limits.noProgress.sameTool no longer leaves an empty noProgress: that would not load.
  • limits.noProgress and limits.noProgress.sameTool are settable by a person through PATCH /config and the config command. config_set cannot 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 is aws (Amazon Polly: options {region, voiceId, engine}; needs polly:SynthesizeSpeech) or openai (/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 emits media.result {kind: "speech", characters}.
  • Amazon Transcribe voice notes in formats other than Ogg/Opus and FLAC (Slack WebM, Teams M4A, MP3) are decoded with ffmpeg first. They were refused before. The image now includes ffmpeg.
  • turn.start carries inputKind: "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, or SOUL.md:). The configuration block gains a context files row naming the files, and config_read's summary lists context.soul.file, context.static, context.volatile and context.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 until no_progress. The first turn after upgrading misses the prompt cache once, because the cached prefix changed.
  • subagents is settable as a whole list by a person or embedder through PATCH /config and changes[], checked as at load (subagent_tool_not_pinned and the rest). The agent's config_set cannot set it. Any edit that unpins a slug a child uses is now refused instead of breaking the next boot.
  • subagents[].timeoutMs bounds a child's routed calls instead of limits.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 until no_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 as tool_personal, with a tool.gated event. PUT /v1/agents/:id/assignee takes channelIds, 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/:id says failed with the load error, or not_running. GET/PATCH /config and PATCH /vars edit its files, answering applied: false until POST /start. The new PUT /v1/agents/:id/workspace/:file replaces 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:4000 endpoint 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 (default shown): the agent's prompt and config_read no 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 whose memory_write saved 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. Emits memory.forgotten {scope, count, messages?}. init pins it; it is not added to policy.allow.
  • A turn records the participant it was taken for (turns.participant_id, migration 31).
  • To stop an earlier conversation from being recalled (includeHistory), use POST /v1/agents/:id/sessions/:key/recall {"recall": false}, which keeps the history (pilot.10), or DELETE /v1/agents/:id/sessions/:key, which removes it and its index entries. A note saved in MEMORY.md is 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.
  • finalText on a turn's result and on turn.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 in finalText.
  • delivery.reply: final (settable with PATCH /config and by the agent's config_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 in message, so an access refusal's assumed-role ARN is no longer in what an embedder shows people. A failed turn's record carries it as errorDetail (store migration 29).
  • channels[].role runs a channel's turns on a model role declared under model:, e.g. WhatsApp on a cheaper model than the web chat. Absent is main. 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 as workspace_unrendered_var, on the agent's warnings and by validate. A placeholder inside an HTML comment, which the model never sees, is not.
  • tools.providers.system.confineReads: true confines file_read, glob and grep to the agent's directory and its writeRoots, a symlink pointing out included, so in a silo one agent cannot read another's notes. Off by default; config_set cannot set it; exec is not bound by it.
  • skills.trusted: [names]: only these skills' scripts become tools, and GET /v1/agents/:id/skills marks each skill trusted. 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_set cannot set it.
  • A tool pinned with config_set works without a restart. When its provider already has it (a slug composio_search just 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.reloaded with ok: 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...
Read more

v0.2.0-pilot.14

v0.2.0-pilot.14 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 07 Oct 16:01

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.
  • finalText on a turn's result and on turn.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 in finalText.
  • Errors take an optional detail: a provider's own words, verbatim. Bedrock now puts AWS's text there instead of in message, so an access refusal's assumed-role ARN is no longer in what an embedder shows people. A failed turn's record carries it as errorDetail (store migration 29).
  • channels[].role runs a channel's turns on a model role declared under model:, e.g. WhatsApp on a cheaper model than the web chat. Absent is main. 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 as workspace_unrendered_var, on the agent's warnings and by validate. A placeholder inside an HTML comment, which the model never sees, is not.
  • tools.providers.system.confineReads: true confines file_read, glob and grep to the agent's directory and its writeRoots, a symlink pointing out included, so in a silo one agent cannot read another's notes. Off by default; config_set cannot set it; exec is 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_set cannot set it.
  • A tool pinned with config_set works without a restart. When its provider already has it (a slug composio_search just 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.reloaded with ok: 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: N ends a turn as no_progress after 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 until no_progress.
  • New event memory.recalled lists 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 and tools/refresh, and got a 404 each time; it now fetches only slugs nobody resolved, so a cold cache still heals.
  • A backup's store.db no longer carries the serve leases of the process it was taken from. A restore that started within 90 seconds of the backup was refused with agent_already_serving, naming a pid that belonged to something else in the new container.

Since 0.2.0-pilot.10

  • GET /v1/backup?include=home adds the rest of the state directory under home/: stopped agents, templates, and anything an embedder keeps beside the store, such as a team drive and its git directory. It never adds the live store.db*, logs/ or the sources/ clone cache. .env files and the host token are added only with include=env, and .git directories only with include=git. backup.json records 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) and tools.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.usage is unchanged.
  • config_set can no longer set any provider's baseUrl, by path or inside a tools.providers value. 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 (or bedrock_credentials_unavailable) and is retried, instead of reaching the turn as model_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. true puts it back. The session then reads recall: false; the client's setRecall sends it.
  • GET /v1/backup?include=env,git adds each agent's .env and .git, and backup.json records each agent's directory. Restoring is documented in the wire spec: with the server stopped, store.db to the store path and each agents/<id>/ to its recorded directory.
  • The wire spec lists what tool.usage's units counts 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 what exec and skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.
  • X_FILE sets X from that file when the CLI starts, unless X is set already. The value never appears in the process's environment block. AWS_* is left to the SDK.
  • Bedrock: when AWS_CONTAINER_CREDENTIALS_FULL_URI is set, the endpoint's own refusal code (for example credit_exhausted) is the turn's error code, terminal, instead of bedrock_credentials_missing.
  • Firecrawl, first-class: tools.providers.web.firecrawl: {} routes web_fetch through Firecrawl's scrape (JavaScript pages come back as markdown) and adds web_crawl and web_map. backend: firecrawl is 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 through ToolContext.meter.
  • An agent asked by another member's agent is told whose agent it is and who is asking. Participants take title and timezone (POST /v1/participants), and both appear in that note.
  • An MCP server's turnHeader sends 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 .env files.
  • GET /v1/agents/:id/assignee reads the assignment back.
  • exec no 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 /config takes {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's removeConfig(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 sent temperature or topP, which they refuse on every turn. A role that sets either gets a model_sampling_unsupported warning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.

Since 0.2.0-pilot.6

  • POST /messages takes role: run that turn on a model role declared under model:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client's send takes it too.
  • A person a...
Read more

v0.2.0-pilot.13

v0.2.0-pilot.13 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 07 Oct 12:41

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: N ends a turn as no_progress after 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 until no_progress.
  • New event memory.recalled lists 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 and tools/refresh, and got a 404 each time; it now fetches only slugs nobody resolved, so a cold cache still heals.
  • A backup's store.db no longer carries the serve leases of the process it was taken from. A restore that started within 90 seconds of the backup was refused with agent_already_serving, naming a pid that belonged to something else in the new container.

Since 0.2.0-pilot.10

  • GET /v1/backup?include=home adds the rest of the state directory under home/: stopped agents, templates, and anything an embedder keeps beside the store, such as a team drive and its git directory. It never adds the live store.db*, logs/ or the sources/ clone cache. .env files and the host token are added only with include=env, and .git directories only with include=git. backup.json records 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) and tools.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.usage is unchanged.
  • config_set can no longer set any provider's baseUrl, by path or inside a tools.providers value. 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 (or bedrock_credentials_unavailable) and is retried, instead of reaching the turn as model_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. true puts it back. The session then reads recall: false; the client's setRecall sends it.
  • GET /v1/backup?include=env,git adds each agent's .env and .git, and backup.json records each agent's directory. Restoring is documented in the wire spec: with the server stopped, store.db to the store path and each agents/<id>/ to its recorded directory.
  • The wire spec lists what tool.usage's units counts 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 what exec and skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.
  • X_FILE sets X from that file when the CLI starts, unless X is set already. The value never appears in the process's environment block. AWS_* is left to the SDK.
  • Bedrock: when AWS_CONTAINER_CREDENTIALS_FULL_URI is set, the endpoint's own refusal code (for example credit_exhausted) is the turn's error code, terminal, instead of bedrock_credentials_missing.
  • Firecrawl, first-class: tools.providers.web.firecrawl: {} routes web_fetch through Firecrawl's scrape (JavaScript pages come back as markdown) and adds web_crawl and web_map. backend: firecrawl is 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 through ToolContext.meter.
  • An agent asked by another member's agent is told whose agent it is and who is asking. Participants take title and timezone (POST /v1/participants), and both appear in that note.
  • An MCP server's turnHeader sends 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 .env files.
  • GET /v1/agents/:id/assignee reads the assignment back.
  • exec no 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 /config takes {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's removeConfig(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 sent temperature or topP, which they refuse on every turn. A role that sets either gets a model_sampling_unsupported warning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.

Since 0.2.0-pilot.6

  • POST /messages takes role: run that turn on a model role declared under model:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client's send takes 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 /messages images do (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 on RawInbound.images.
  • Two members' agents may delegate to each other (delegation.to both ways). This was refused at load as team_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 /config sets delegation.offer and delegation.to. An offer change reloads the agents that may ask, and each one is reported under peers.
  • 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 of list of object alone.

Since 0.2.0-pilot.5

  • Bedrock: Claude 4.7 and later (Sonnet 5.5, Opus 5.5) take reasoningEffort as adaptive thinking with an effort instead of the thinking budget they refuse. reasoningEffort gains xhigh and max. none is each model's own off switch, or low effort where thinking cannot be turned off, said at load. temperature and topP are not sent to models that refuse them. openai.* models get the effort as reasoning: {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_filter finish) 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 (or subagents[].model) runs children on a cheaper mo...
Read more

v0.2.0-pilot.12

v0.2.0-pilot.12 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 07 Oct 11: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 and tools/refresh, and got a 404 each time; it now fetches only slugs nobody resolved, so a cold cache still heals.
  • A backup's store.db no longer carries the serve leases of the process it was taken from. A restore that started within 90 seconds of the backup was refused with agent_already_serving, naming a pid that belonged to something else in the new container.

Since 0.2.0-pilot.10

  • GET /v1/backup?include=home adds the rest of the state directory under home/: stopped agents, templates, and anything an embedder keeps beside the store, such as a team drive and its git directory. It never adds the live store.db*, logs/ or the sources/ clone cache. .env files and the host token are added only with include=env, and .git directories only with include=git. backup.json records 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) and tools.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.usage is unchanged.
  • config_set can no longer set any provider's baseUrl, by path or inside a tools.providers value. 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 (or bedrock_credentials_unavailable) and is retried, instead of reaching the turn as model_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. true puts it back. The session then reads recall: false; the client's setRecall sends it.
  • GET /v1/backup?include=env,git adds each agent's .env and .git, and backup.json records each agent's directory. Restoring is documented in the wire spec: with the server stopped, store.db to the store path and each agents/<id>/ to its recorded directory.
  • The wire spec lists what tool.usage's units counts 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 what exec and skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.
  • X_FILE sets X from that file when the CLI starts, unless X is set already. The value never appears in the process's environment block. AWS_* is left to the SDK.
  • Bedrock: when AWS_CONTAINER_CREDENTIALS_FULL_URI is set, the endpoint's own refusal code (for example credit_exhausted) is the turn's error code, terminal, instead of bedrock_credentials_missing.
  • Firecrawl, first-class: tools.providers.web.firecrawl: {} routes web_fetch through Firecrawl's scrape (JavaScript pages come back as markdown) and adds web_crawl and web_map. backend: firecrawl is 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 through ToolContext.meter.
  • An agent asked by another member's agent is told whose agent it is and who is asking. Participants take title and timezone (POST /v1/participants), and both appear in that note.
  • An MCP server's turnHeader sends 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 .env files.
  • GET /v1/agents/:id/assignee reads the assignment back.
  • exec no 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 /config takes {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's removeConfig(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 sent temperature or topP, which they refuse on every turn. A role that sets either gets a model_sampling_unsupported warning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.

Since 0.2.0-pilot.6

  • POST /messages takes role: run that turn on a model role declared under model:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client's send takes 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 /messages images do (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 on RawInbound.images.
  • Two members' agents may delegate to each other (delegation.to both ways). This was refused at load as team_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 /config sets delegation.offer and delegation.to. An offer change reloads the agents that may ask, and each one is reported under peers.
  • 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 of list of object alone.

Since 0.2.0-pilot.5

  • Bedrock: Claude 4.7 and later (Sonnet 5.5, Opus 5.5) take reasoningEffort as adaptive thinking with an effort instead of the thinking budget they refuse. reasoningEffort gains xhigh and max. none is each model's own off switch, or low effort where thinking cannot be turned off, said at load. temperature and topP are not sent to models that refuse them. openai.* models get the effort as reasoning: {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_filter finish) 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 (or subagents[].model) runs children on a cheaper model. Their usage rows and model.result events say role: subagent.
  • A subagent's events carry parentTurnId and parentSessionKey, and handoff.start/handoff.result gain kind, name and the parent's callId. A turn's stream includes its subagents' events with children: true (also on the client's stream()), and still ends on its own turn.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_artifact must 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:subagents measures routed calls against keeping the work in the parent's context (evals/subagents/).
  • The web chat shows a quick reply as it arri...
Read more

v0.2.0-pilot.9

v0.2.0-pilot.9 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Oct 12:09

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 what exec and skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.
  • X_FILE sets X from that file when the CLI starts, unless X is set already. The value never appears in the process's environment block. AWS_* is left to the SDK.
  • Bedrock: when AWS_CONTAINER_CREDENTIALS_FULL_URI is set, the endpoint's own refusal code (for example credit_exhausted) is the turn's error code, terminal, instead of bedrock_credentials_missing.
  • Firecrawl, first-class: tools.providers.web.firecrawl: {} routes web_fetch through Firecrawl's scrape (JavaScript pages come back as markdown) and adds web_crawl and web_map. backend: firecrawl is 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 through ToolContext.meter.
  • An agent asked by another member's agent is told whose agent it is and who is asking. Participants take title and timezone (POST /v1/participants), and both appear in that note.
  • An MCP server's turnHeader sends 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 .env files.
  • GET /v1/agents/:id/assignee reads the assignment back.
  • exec no 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 /config takes {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's removeConfig(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 sent temperature or topP, which they refuse on every turn. A role that sets either gets a model_sampling_unsupported warning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.

Since 0.2.0-pilot.6

  • POST /messages takes role: run that turn on a model role declared under model:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client's send takes 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 /messages images do (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 on RawInbound.images.
  • Two members' agents may delegate to each other (delegation.to both ways). This was refused at load as team_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 /config sets delegation.offer and delegation.to. An offer change reloads the agents that may ask, and each one is reported under peers.
  • 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 of list of object alone.

Since 0.2.0-pilot.5

  • Bedrock: Claude 4.7 and later (Sonnet 5.5, Opus 5.5) take reasoningEffort as adaptive thinking with an effort instead of the thinking budget they refuse. reasoningEffort gains xhigh and max. none is each model's own off switch, or low effort where thinking cannot be turned off, said at load. temperature and topP are not sent to models that refuse them. openai.* models get the effort as reasoning: {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_filter finish) 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 (or subagents[].model) runs children on a cheaper model. Their usage rows and model.result events say role: subagent.
  • A subagent's events carry parentTurnId and parentSessionKey, and handoff.start/handoff.result gain kind, name and the parent's callId. A turn's stream includes its subagents' events with children: true (also on the client's stream()), and still ends on its own turn.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_artifact must 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:subagents measures 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 send takes chunks: true to 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 --continue and a bare run --session no 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 --plain prints 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 observationMaxTokens is stored whole, and its marker names the id to read it with artifact_read. Reading an untrusted result back is untrusted too, so it no longer reopens the write gate.
  • GET /v1/agents/:id answers a stopped agent with the listing's status: "disabled" row instead of 404. Routes that act on it are still 404.
  • The workspace_rule_budget refusal names the lines it counted and their files. context.rules.onExceed is settable through PATCH /config (by a person), so a misread line no longer holds every reload.
  • Under tools.dialect: native a skill script (skill.pdf.extract) is sent as skill__pdf__extract instead 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 /messages takes images: 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 with model_no_vision, and capabilities.vision can say otherwise. The client's send takes images too.
  • A schedule takes tools.allow (the phase grammar), timeoutMs and maxSteps, in the manifest and over the API. They only narrow the agent's own tools and limits; an allow entry naming nothing is schedule_tool_unknown. POST …/schedules/:sid/run runs with the same limits as a timed fire.
  • POST /messages takes runtimeNote: your application's note about the message (...
Read more

v0.2.0-pilot.11

v0.2.0-pilot.11 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Oct 14:47

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=home adds the rest of the state directory under home/: stopped agents, templates, and anything an embedder keeps beside the store, such as a team drive and its git directory. It never adds the live store.db*, logs/ or the sources/ clone cache. .env files and the host token are added only with include=env, and .git directories only with include=git. backup.json records 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) and tools.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.usage is unchanged.
  • config_set can no longer set any provider's baseUrl, by path or inside a tools.providers value. 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 (or bedrock_credentials_unavailable) and is retried, instead of reaching the turn as model_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. true puts it back. The session then reads recall: false; the client's setRecall sends it.
  • GET /v1/backup?include=env,git adds each agent's .env and .git, and backup.json records each agent's directory. Restoring is documented in the wire spec: with the server stopped, store.db to the store path and each agents/<id>/ to its recorded directory.
  • The wire spec lists what tool.usage's units counts 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 what exec and skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.
  • X_FILE sets X from that file when the CLI starts, unless X is set already. The value never appears in the process's environment block. AWS_* is left to the SDK.
  • Bedrock: when AWS_CONTAINER_CREDENTIALS_FULL_URI is set, the endpoint's own refusal code (for example credit_exhausted) is the turn's error code, terminal, instead of bedrock_credentials_missing.
  • Firecrawl, first-class: tools.providers.web.firecrawl: {} routes web_fetch through Firecrawl's scrape (JavaScript pages come back as markdown) and adds web_crawl and web_map. backend: firecrawl is 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 through ToolContext.meter.
  • An agent asked by another member's agent is told whose agent it is and who is asking. Participants take title and timezone (POST /v1/participants), and both appear in that note.
  • An MCP server's turnHeader sends 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 .env files.
  • GET /v1/agents/:id/assignee reads the assignment back.
  • exec no 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 /config takes {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's removeConfig(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 sent temperature or topP, which they refuse on every turn. A role that sets either gets a model_sampling_unsupported warning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.

Since 0.2.0-pilot.6

  • POST /messages takes role: run that turn on a model role declared under model:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client's send takes 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 /messages images do (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 on RawInbound.images.
  • Two members' agents may delegate to each other (delegation.to both ways). This was refused at load as team_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 /config sets delegation.offer and delegation.to. An offer change reloads the agents that may ask, and each one is reported under peers.
  • 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 of list of object alone.

Since 0.2.0-pilot.5

  • Bedrock: Claude 4.7 and later (Sonnet 5.5, Opus 5.5) take reasoningEffort as adaptive thinking with an effort instead of the thinking budget they refuse. reasoningEffort gains xhigh and max. none is each model's own off switch, or low effort where thinking cannot be turned off, said at load. temperature and topP are not sent to models that refuse them. openai.* models get the effort as reasoning: {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_filter finish) 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 (or subagents[].model) runs children on a cheaper model. Their usage rows and model.result events say role: subagent.
  • A subagent's events carry parentTurnId and parentSessionKey, and handoff.start/handoff.result gain kind, name and the parent's callId. A turn's stream includes its subagents' events with children: true (also on the client's stream()), and still ends on its own turn.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_artifact must 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:subagents measures 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 send takes chunks: true to 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 --continue and a bare run --session no longer fail with "Cannot access 'source' before initialization" when no host is running (broken sinc...
Read more

v0.2.0-pilot.10

v0.2.0-pilot.10 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 06 Oct 14: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) and tools.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.usage is unchanged.
  • config_set can no longer set any provider's baseUrl, by path or inside a tools.providers value. 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 (or bedrock_credentials_unavailable) and is retried, instead of reaching the turn as model_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. true puts it back. The session then reads recall: false; the client's setRecall sends it.
  • GET /v1/backup?include=env,git adds each agent's .env and .git, and backup.json records each agent's directory. Restoring is documented in the wire spec: with the server stopped, store.db to the store path and each agents/<id>/ to its recorded directory.
  • The wire spec lists what tool.usage's units counts 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 what exec and skill scripts see. It is off by default, so nothing changes until a manifest sets it, and the agent cannot change it.
  • X_FILE sets X from that file when the CLI starts, unless X is set already. The value never appears in the process's environment block. AWS_* is left to the SDK.
  • Bedrock: when AWS_CONTAINER_CREDENTIALS_FULL_URI is set, the endpoint's own refusal code (for example credit_exhausted) is the turn's error code, terminal, instead of bedrock_credentials_missing.
  • Firecrawl, first-class: tools.providers.web.firecrawl: {} routes web_fetch through Firecrawl's scrape (JavaScript pages come back as markdown) and adds web_crawl and web_map. backend: firecrawl is 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 through ToolContext.meter.
  • An agent asked by another member's agent is told whose agent it is and who is asking. Participants take title and timezone (POST /v1/participants), and both appear in that note.
  • An MCP server's turnHeader sends 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 .env files.
  • GET /v1/agents/:id/assignee reads the assignment back.
  • exec no 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 /config takes {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's removeConfig(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 sent temperature or topP, which they refuse on every turn. A role that sets either gets a model_sampling_unsupported warning at load, as Claude 4.7 and later do. gpt-oss and Nova still get both.

Since 0.2.0-pilot.6

  • POST /messages takes role: run that turn on a model role declared under model:, as a schedule does. An undeclared role is refused before the turn starts (model_role_unknown). The client's send takes 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 /messages images do (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 on RawInbound.images.
  • Two members' agents may delegate to each other (delegation.to both ways). This was refused at load as team_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 /config sets delegation.offer and delegation.to. An offer change reloads the agents that may ask, and each one is reported under peers.
  • 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 of list of object alone.

Since 0.2.0-pilot.5

  • Bedrock: Claude 4.7 and later (Sonnet 5.5, Opus 5.5) take reasoningEffort as adaptive thinking with an effort instead of the thinking budget they refuse. reasoningEffort gains xhigh and max. none is each model's own off switch, or low effort where thinking cannot be turned off, said at load. temperature and topP are not sent to models that refuse them. openai.* models get the effort as reasoning: {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_filter finish) 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 (or subagents[].model) runs children on a cheaper model. Their usage rows and model.result events say role: subagent.
  • A subagent's events carry parentTurnId and parentSessionKey, and handoff.start/handoff.result gain kind, name and the parent's callId. A turn's stream includes its subagents' events with children: true (also on the client's stream()), and still ends on its own turn.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_artifact must 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:subagents measures 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 send takes chunks: true to 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 --continue and a bare run --session no 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 --plain prints 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 observationMaxTokens is stored whole, and its marker names the id to read it with `art...
Read more