Skip to content

Agent platform

Agent platform

Agent platform is the Bolt-owned loop and UI for agentic workloads. It executes the agent loop — multi-step reasoning, tool calls, and subagents — that the workspace authors under Agents . Colony admits each loop invocation into a one-shot worker. Model and tool waits resume within that same invocation; its slot remains assigned while only active worker CPU is metered. Colony also supplies the trusted host tools the workspace opts into.

Bolt-owned, hosted on Colony
The agent loop, /agent UI, and transcripts ship in @norbital-ai/bolt . Colony is the managed host: it binds ai , admits each loop iteration, meters usage, and supplies trusted host tools.
Authoring lives in the Authoring section
How to author the agent — instructions, envoys, tools, and skills — is documented under Agents . This page covers the loop, the permission model, and host tools.

One loop, two doors

Every interactive conversation — web chat or an envoy message — goes through the same agent loop, whose shared system prompt is the workspace’s `src/+agents.md`. What differs is the door it came in by: who the agent acts as, and which instructions and tools apply. Automations are separate: deterministic handlers that call `api.infer` when they need model judgement; they do not spawn agent sessions.

  web chat (signed-in user)      Telegram / WhatsApp
        │                              │
        ▼                              ▼
  persist + admit                persist + admit
        │                              │
        └──────────────┬───────────────┘
                       ▼
  ┌────────────────────────  Bolt agent loop  ────────────────────────┐
  │  each invocation uses one one-shot worker and capacity slot       │
  │  await infer yields; host I/O is not worker CPU, then the same     │
  │  invocation resumes; the worker and slot remain assigned          │
  │                                                                    │
  │  tools: read_collection · write_collection · workspace tools      │
  │         skills (list_skills · read_skill) · host tools (opt-in)   │
  └───────────────┬───────────────────────┬───────────────────────────┘
                  │                       │
                  ▼                       ▼
          tenant database          host AI binding
          (chat_session             (inference between
           aggregate)                worker yields)

Who can use Agent

  • Pro — Agent plus Workspace Studio authoring
  • Standard — no Agent or sandbox access

AI usage is metered separately from the workspace base fee. See pricing .

The permission model

The central rule: permission bounds the agent, not its tool list.

Every data read and write the agent makes — through read_collection and write_collection — runs unelevated: the same policies, hooks, and approval gates apply as if the acting person clicked through the app themselves. The agent is a faster hand on the same controls, never a wider set of them.

DoorThe agent acts asBound by
Web chatThe signed-in userThat user’s permissions
Envoy messageThe envoy’s own agent identityThe policies the envoy declares

Configure the agent: src/+agents.md

The workspace’s shared system prompt is the whole of src/+agents.md at the workspace root. It is the system message of every agent turn, web and envoy alike: what the collections mean, what the company does, and house rules for tone and escalation. An envoy’s `task` is its own standing instruction on top of it.

# src/+agents.md
You are the agent of the operations workspace. Ground every answer in
the data. Report figures in MYR. Never guess — say so when data is
missing.

The authoring surface — envoys, skills, and tools — lives in Workspace source; this page covers the loop, the funnel, and host tools.

Envoys: the agent on someone else’s wire

An envoy is the agent reached over Telegram or WhatsApp — a conversation with a person the workspace may not have a user row for. The transport itself stays host-supplied: the workspace declares the envoy in source, and Colony owns the credentials and the socket. The full declaration contract lives in Envoys .

// src/envoys/+sales_desk.ts
export default {
	transport: 'telegram',
	audience: 'public',
	policies: ['sales_rep'],
	groupMessages: 'disabled',
	task: 'Answer order and quotation questions for the sales desk.'
} satisfies Envoy;
  • transport — the wire that reaches it ( telegram or whatsapp ), checked against the transport’s identity canonicalisation at runtime.
  • policies — the policies the envoy acts under. An envoy may be a group chat, so there is no single person to inherit permissions from; the run acts as the envoy’s own subject. An envoy whose policies hold no grants can do nothing.
  • task — the envoy’s standing instruction, on top of the workspace’s `src/+agents.md`.
Every envoy has one workbench; every chat owns its documents
A public envoy shares one workbench across its conversations, while every chat owns its transcript, inbound buffer, lease, and documents. Narrow ingress envoys can declare `delegation: 'disabled'` sandbox_bash to refuse delegation entirely. Everything an envoy may reach is what the policies it names grant — never more.

Agent tools

The agent always has Bolt’s built-in tools:

  • describe_workspace — what the workspace contains
  • read_collection — reads apply the subject’s policy grants
  • write_collection — create/update/delete only where the policy grants it, create/update/delete
  • list_skills / read_skill — progressive disclosure of documentation (see Skills )
  • spawn_subagent — a child turn that cannot spawn another

Workspaces author their own tools — a typed function the agent can call, running through the same scoped API as a hook, so policies and field masks still apply:

// src/capabilities/tools/+product_lookup.ts
import { defineAgentTool } from '@norbital-ai/bolt/authoring';
import { Effect, Schema } from 'effect';

export default defineAgentTool({
	description: 'Returns one product by id, with its current stock level.',
	input: Schema.Struct({ productId: Schema.String }),
	run: (api, { productId }) =>
		Effect.gen(function* () {
			const product = yield* api.db.query.products.findFirst({
				where: { id: { eq: productId } }
			});
			return product ?? null;
		})
});

Tool files are discovered by name — +<lower_snake_case>.ts — under src/capabilities/tools/ . Built-in names are reserved: a workspace tool called read_collection is a compile error.

More tools

The tool surface keeps growing. Three tiers cover it:

  • Built-in tools — shipped with every bolt, always available
  • Custom tools — workspace tools declared with defineAgentTool
  • Host tools — trusted host-process operations. Sandbox-gated tools arrive when a sandbox is bound; others are opt-in

The tool funnel

Every model that can call tools goes through one assembly path. Two surfaces feed it:

  • agent — interactive chat, envoys, subagents. Owns a chat_session transcript.
  • infer — api.infer in hooks, automations, remotes. Ephemeral messages only; never a transcript. Read-only: no write_collection, authoring, sandbox, MCP, or spawn_subagent.

What a turn may call, in order:

  1. Platform read builtins — describe_workspace, read_collection, list_skills, read_skill. read_collection applies the subject’s read grants row by row.
  2. Platform write — write_collection, offered when the subject holds create/update/delete grants on the collection; approval gates and field masks apply exactly as in the app.
  3. Platform coordination — spawn_subagent, offered once per turn to the root session; a subagent cannot spawn further subagents.
  4. Workspace tools and MCP servers — from `capabilities.tools` and `capabilities.mcp` of the policies the subject holds, never from a separate allowlist.
  5. Skills — from `capabilities.skills`, granted like tools; below them, sandbox host tools when the turn has a bound sandbox, then other host tools the host supplied.

`api.infer` surfaces no tools at all — no write_collection, no authoring, no sandbox, no MCP, no spawn_subagent.

Host tools

Host tools are trusted operations that run in the host process with the host’s credentials — never in tenant code. On Colony these are the sandbox coding and deployment tools, acting as the tenant’s Builder principal. Sandbox-gated tools are supplied by the funnel when a sandbox is bound, not by listing them in hostTools . Other host tools still require an explicit name; the list is checked against the host’s inventory at startup, and a tool named but not supplied refuses the workspace to boot.

WhatsApp, web, and every other agent profile receive sandbox tools when a sandbox is bound. denyTools is typesafe over workspace tools and platform builtins; naming a sandbox_* tool there is an error.

Skills: documentation the agent reads on demand

Skills are markdown documentation the agent loads when it needs it, instead of carrying every explanation in every prompt. A skill is a directory under `src/capabilities/skills/` with a SKILL.md entry (name and description frontmatter) plus optional reference files:

src/capabilities/skills/
└── approvals/
    ├── +skill.md          # what the agent needs to know about approvals
    └── references/
        └── policy-matrix.md

The agent calls list_skills to see what exists, then read_skill to load the body or one reference file. Bolt ships norbital-platform and authoring-tenant-workspace ; a workspace skill that shadows a shipped name is refused at compile time, so the platform’s own account of how approvals work can never be replaced.

Drafting, never releasing

When Agent helps with structural changes, work stays in the edit source zone . Builders still sync preview and go live manually — Agent can never release to production, and Workspace Studio release controls are builder-only. Agent respects the same boundary.

Conversations are data

Each agent conversation is one tenant-database aggregate ( chat_session ) containing ordered messages, nested turns, title, status and usage. One ordinary sync subscription carries every mutation to the agent UI; the aggregate is owned by the requestor and scoped by policy. Agent cannot bypass approval gates, record locks, or redaction, and usage is reported to billing after each turn.

Example prompts

  • “Show me all projects created this week that are marked urgent.”
  • “What fields exist on the Suppliers collection?”
  • “Take me to payroll approval settings.”
  • “Summarize open tasks assigned to my team.”

Best practices

  • Use precise collection, team, and app names in prompts.
  • Write task at the workspace root — the shared system message, where the agent gets its world model. src/+agent.ts
  • Add workspace skills for domain rules the agent must follow; the agent reads them when they matter.
  • Review draft source before sync and go live, even when Agent authored it.
  • Agent access is included in the workspace base fee; the AI you use is metered.