workspace.yml
Every field, and what it changes.
Every field, and what it changes.
name: Acme Back Office # shown in the UI; also {{tenant_name}}
icon: 🗂 # sidebar icon
brand_color: '#2F5D62' # accent throughout the UI
apps:
analyst: # the app id, used in URLs and @mentions
name: Ada # display name; also {{persona_name}}
role: Data analyst # shown under the name
soul: agents/analyst/SOUL.md
tools: agents/analyst/tools/
model: gpt-5.4-codex
max_turns: 10
group: backoffice # backoffice | customer
type: agentino # which runtime runs it
channels:
- id: general
label: general
type: chat # chat | activity | addon
gates:
rules:
- gate: confirm
tools: [raise_purchase_order]
message: "Raise this purchase order?"
The fields that catch people out
group decides whether an agent is offered for @mention. A customer
agent is a public-facing chat persona and is deliberately not mentionable
from the back office. If an agent never answers when mentioned, this is why.
type defaults to agentino. Set it to codex, claude_code, pi or
openclaw to have that CLI run the turn instead. Nothing else changes.
max_turns caps the tool-calling loop. Too low and the agent runs out of
turns mid-task and answers with whatever it has; too high and a confused agent
burns tokens. Ten is a reasonable default for a tool-using agent.
channels with type: chat are seeded with every agent as a member.
activity and addon channels are UI surfaces, not conversations, and are not
seeded.
Every top-level key
name | Shown in the UI, and substituted for {{tenant_name}} |
icon | Sidebar icon |
brand_color · sidebar_color | Accent and sidebar background |
apps | The agents. See below |
channels | Chat, activity and add-on surfaces |
users | Workspace seats — who the UI thinks you are |
user | A single default seat, if you do not need several |
providers | Named model endpoints an app can select |
settings | Sections rendered on the settings page |
suggestions | Opening questions a dialog client offers |
routines | Path to the scheduled-work file |
external_channels | Bindings to Telegram, WhatsApp and friends |
audio | Transcription backend |
tenant_id | Overrides the directory name |
demo | Seed messages, for a workspace shown before it has history |
A provider is how a workspace points at a model without naming an endpoint in code:
providers:
main:
base_url: ${AI_BASE_URL}
api_key: ${AI_API_KEY}
provider: openai-codex
Every per-app key
name · role · avatar · color | How the agent appears |
description | One line, shown under the name |
type | Which runtime executes a turn |
enabled | Set false to keep the config and hide the agent |
group | backoffice, customer or your own label. Customer agents are not offered for @mention |
soul | Path to the instructions |
tools | Path to a tool directory |
shared_tools_dirs | Extra directories, shared between agents |
std_bundles | Built-in tool bundles to include |
require_tool_use | Reject a turn that answers without calling a tool |
model | Overrides the provider default |
max_turns | Cap on the tool-calling loop |
gates | Preconditions on tool calls |
response_filter | module.path:callable the app owns, called on each reply |
endpoint | For a runtime that reaches an agent over HTTP |
Environment interpolation
Any value may use ${VAR} or ${VAR:-default}, expanded at load. Keep secrets
out of the file and let the environment supply them.