Skip to content

Guilds and agents ​

A guild owns zero or more agents, guild-level artifacts, and one group chat. The operator can create an empty guild and add agents later. A guild has an optional about (at most 200 characters) and an optional description (at most 8000 characters). Both are columns on guilds. max_agents (default 15) is how many agents the guild can hold. Creating another agent, or applying a recipe that would pass that count, is refused. The Settings tab edits name, about, description, max_agents, visibility, routines, and the group-chat message limit. An agent has an optional focus (at most 100 characters). About, description, and focus are attached to the hydrated system prompt's State snapshot (group.about, group.description, and each member's focus) so members know the guild's goal and each other's role. Focus also seeds that agent's task at create. An agent also has optional wake_triggers (at most 500 characters): the untagged group-chat messages it should wake for, written to complete "Wake me when…". Empty means its focus stands in. Wake triggers are not hydrated into the system prompt and are not an option of the recipient Choice (Group chat). Every organisation has the artifact store. Notes exist at agent, guild, and org; reach over them is the four grant bindings on the agent. Collections are organisation-level tables. A table that belongs to the guild (guild_id) is written by every member and reached by nobody else. An organisation table is reached through a read or write grant the operator sets (Notes and collections). Scripts are agent-level artifacts.

A guild is org or private. Org-visible guilds are listed to every organisation member. A private guild is listed and readable only by its operators. The create modal defaults to private.

Repositories ​

A guild has git repositories (guild_repositories: guild, name matching ^[a-z][a-z0-9_-]{0,62}$ and unique in the guild, url, default_branch, optional connection_id, and GitHub's github_id for one added through a login). Each coding agent of the guild clones them into /home/agent/repos/<name> (Runs). The guild's Settings tab adds and removes them; any operator who sees the guild may.

text
GET    /api/guilds/:id/repositories
POST   /api/guilds/:id/repositories
DELETE /api/guilds/:id/repositories/:repository_id

GET returns { repositories, github_connections }. GitHub-backed repositories are picked on the GitHub integration (Tools) at organisation, guild, or agent scope; a narrower scope inherits the wider login's set until it connects its own. repositories are this guild's extra git URLs (anonymous, or a login that is not the effective one). github_connections are the connected GitHub logins the operator can see in the organisation.

POST takes { name, url, default_branch?, connection_id? } and returns 201 with the repository; a name the guild already has is 409. url is an https git URL without credentials, query, or fragment. With a connection_id, the connection must be one of those GitHub logins, url must be https://github.com/<owner>/<repository>, and the orchestrator checks that the installation reaches that repository (422 otherwise); default_branch then defaults to the one GitHub reports, and GitHub's id for the repository is recorded. Without a connection it defaults to main, the repository is cloned anonymously, and the orchestrator gives the agent no credential for it, so only a public repository clones. The Settings form offers the connected GitHub logins for a github.com URL and picks the first by default. A repository payload carries its connection (id, status, account_hint) or null. Removing a repository leaves the working trees already cloned. Deleting a guild deletes its repositories; deleting a connection deletes the repositories added through it.

A guild's git_author_email is the commit author email coding agents write into git at each generation. Empty (the default) uses <agent id>@agents.guilds.run. A non-empty value must be a single email address and must not use a .invalid domain. Deploy services such as Vercel identify the author from that address: set it to a verified email on the GitHub account that owns the project. PUT /api/guilds/:id accepts git_author_email; omitted leaves the stored value, and an empty string clears it. The Settings tab edits it next to Repositories.

Coding agents never share a working tree: each clones its own, and work moves between agents as branches on the remote. The coding section of the system prompt has an agent work on a branch named agent/<its name>/<topic>, open pull requests with gh pr create, and record the URL where the work item is tracked. A guild that divides coding work between roles does it with what every guild has: a collection of work items (state, repository, branch, pull request, owner) that agents find with record_list and claim with record_update, a tagged group_post that names the item and the branch for the next agent, and a guild note per repository holding what the code does not say (layout, build and test commands, conventions), embedded in each coding agent's Task.

Operators ​

Operators are the people a guild works for (guild_operators: guild, user, role). The role is admin or operator. Whoever creates a guild, from the create modal or a recipe apply, is its first admin. Operators are organisation members; leaving the organisation removes them.

  • Agents see the roster as State group.operators (name, role) and tag an operator by name, or every operator with @user (Group chat).
  • Each operator's inbox holds the guild's open issues and the messages that tag them (Operator app).
  • Only an admin adds operators, changes roles, removes operators, changes visibility, or deletes the guild. Every other guild action is open to anyone who can see the guild.
  • A guild keeps at least one admin: demoting or removing the last admin is 409, and so is removing from the organisation, or deleting, a user who is the only admin of a guild.
  • Agents and operators share the guild's tag names. Creating or renaming an agent to an operator's name, or adding an operator named like one of the guild's agents, is 409.

PUT /api/guilds/:id/operators/:user_id with { role } adds an organisation member or changes their role; DELETE /api/guilds/:id/operators/:user_id removes one. Both return the guild. Guild payloads carry operators (user_id, name, role, oldest first).

Each guild carries a consecutive-agent-message limit for group chat (group_agent_message_limit; a new guild starts at 200), editable from the guild header and the Settings tab.

routines_enabled (default true) is the guild switch for schedule wake-ups. While it is false the ticker skips every schedule in the guild. Each schedule keeps its own paused flag. Turning the switch back on recomputes next_run_at from now for unpaused schedules that are already due, so missed wake-ups are not replayed.

Every agent belongs to exactly one guild for its entire life. Names are globally unique and match ^[a-z][a-z0-9-]{0,62}$. The name user is reserved for the tag that reaches every operator in group chat. The Settings tab can change a name after create. Database ids stay stable across a rename, and if a name is later reused after delete. Display paths use those ids.

Configuration and appearance ​

Agent configuration is seventeen required keys: model, temperature, max_tokens, max_steps, max_tool_calls, max_input_tokens, keep_tool_result_generations, max_scripts, max_workspace_mib, cli, browser, browser_language, coding, scripting, memory, thinking_level, box. Unknown keys are rejected; missing ones take defaults (temperature 1, 8192 tokens, 30 steps, 50 tool calls, 100000 input tokens, 1 live generation of tool results, 10 scripts, 10240 MiB of workspace, CLI, scripting, and Memory on, thinking none, browser language en-US). A missing box follows the flags, and missing flags follow the box: standard turns browser and coding on, lite turns both off, and a payload that names neither makes a lite agent. The box alone is enough to create an agent. An agent created with coding on and no step or tool-call limit starts with 200 steps and 200 tool calls instead. The create and Settings forms offer the box under Box, Lite or Standard, and CLI, scripting, and Memory under Agent capabilities. A new agent is Lite; picking Standard turns browser and coding on together, with CLI, scripting, and the coding budgets. CLI, scripting, and Memory start on, and the operator can turn any of them off on either box.

  • max_scripts is how many reusable Python scripts the agent may keep. Creating a new name past that count is refused; replacing an existing name is not. Lowering the cap below the current count is allowed and only blocks further creates. Applying a recipe that would pass the count is refused. The Settings tab edits it and can remove every script.
  • max_workspace_mib is how large this agent's workspace may grow, in MiB. Stored default is 10240 (10 GiB). After each generation the orchestrator measures the workspace and stores it as workspace_mib on the agent; the Usage tab shows used against this cap. Above the effective cap (the agent's max, and never above the host's WORKSPACE_MAX_MIB, default 10240) the next generation fails at start with workspace.full until the operator frees space from the CLI tab or raises the agent's max.
  • max_tool_calls is how many tool invocations a run may execute before it ends.
  • max_input_tokens is the largest prompt the run may send to the model client after tool-result stubbing; above that the run stops and asks for a new one. A coding run hands off at 70% of it and continues in a new run (Runs).
  • keep_tool_result_generations is how many user turns, including the current one, keep full tool output in the model prompt. Default 1: large tool results from earlier turns are stubbed. The stored transcript is unchanged (Runs).
  • cli is whether the operator can open a terminal on this agent's machine. It selects the CLI tab and the CLI API. It is not a binding. The runtime image already includes ttyd; the flag only exposes it.
  • box is the machine the agent runs on, lite or standard, and follows the two flags below: standard when browser or coding is on, lite when both are off. A payload whose box disagrees with its flags is refused; a stored config without the key reads as the box its flags call for. Lite is the small guest (0.5 CPU, 256Mi, the lite image: Python, the scripts launcher, ttyd) and never has shell, the code tools, a package manager, or a browser. Standard is the large guest (2 CPU, 4Gi, the standard image). Changing the box replaces the sandbox. An agent on standard with only one of the two flags keeps the other off; the unused toolchain stays in the image and is not offered.
  • browser is whether this agent's machine includes Chromium: it selects the Browser pane, a live 1280×720 Chromium/noVNC session on the standard box, and the eight Playwright tools on that agent's runs. It is not a binding. The two runtime images are instance-wide.
  • browser_language is Chrome's UI and Accept-Language when browser is on: a tag from a fixed list, stored default en-US. Changing it destroys an idle sandbox so the next ensure starts Chrome in that language. Timezone still comes from the sandbox egress IP.
  • coding makes the agent a coding agent: the standard box with HOME at /home/agent, so package caches, toolchains, and git configuration persist across idle stops, the code tools (Tools and connectors), and the coding section of the system prompt. It is independent of browser: an agent that debugs a web front end has both. It is not a binding. The organisation policy's max_coding_agents bounds how many agents have it; core sets no bound, and where an edition's policy does, creating a coding agent, or turning the flag on, is refused above it.
  • scripting is whether this agent may keep and run Python scripts. It selects the State's Scripts view and the five script tools. Those tools remain bindings when the flag is on; when it is off they are not offered, whatever the bindings say. It is not itself a binding.
  • memory is whether this agent hydrates Memory and may call memory_write. When it is off the opening system prompt omits the Memory section and the memory instructions in Guidelines, and memory_write is not offered, whatever the bindings say. The Memory tab stays. Missing means on. It is not itself a binding.
  • thinking_level is none, low, medium, or high. Stored default is none. When it is not none the model request carries reasoning: { effort } (and reasoning_effort). The picker greys it out only for catalog models flagged thinking: false, and saves none for them.
  • temperature is always sent. The picker greys it out only for catalog models flagged temperature: false, whose provider drops the value.
  • attachments on GET /api/models is true when that catalog entry accepts image parts. The Chat composer always shows a paperclip; it is disabled with a tooltip when the flag is false. DeepSeek-V4.1-Flash and every Kimi Code id accept them; open-weight Qwen3.8 2.4T does not. Group chat does not take attachments.

Native tools and sandbox env values come from bindings (instance → organisation → guild → agent), not from this JSON. Pinned prices tickers live on that login in Tools. The browser, code, (when scripting is off) script, and (when memory is off) memory tools follow their flags, not only bindings. Toggling browser or coding, or changing browser_language while browser is on, destroys an idle sandbox so the next generation recreates it; a generating agent keeps its sandbox until the generation ends. Toggling cli, scripting, or memory does not replace the sandbox.

model is a catalog id ({provider}/{model}). The operator assigns one catalog entry per agent. New agents default to deepinfra/zai-org/GLM-5.3-Flash. GET /api/models returns that catalog for the picker, including the default, each provider's kind (marketplace or coding), whether a model is coding_only and requires_org_key, and whether it accepts attachments. Kimi Code ids (kimi/…) are only valid when coding is on and the organisation has a Kimi Code key. Studio and Builder stay on marketplace models. Each run freezes the chosen string.

Appearance lives beside config, not inside it. avatar_shape is a seed matching ^[a-z0-9][a-z0-9:-]{0,62}$, optionally prefixed with a DiceBear style (critters, cameo, pixelbot, bottts-neutral, or clay) as style:seed. With no prefix the renderer uses clay. The stored default is teardrop (clay). The create dialog starts on a random critters:<seed> in the signal identity colour (#1fafd1). avatar_color is a six-digit hex (default #7c5cff). The orchestrator renders GET /avatars/:style.svg?seed=…&color=… with apps/orchestrator/src/avatars/; the create dialog and agent Settings pick a style, a random seed, and one of six identity colours. PUT /api/agents/:id/config accepts the config keys plus optional name, avatar_shape, avatar_color, focus, and wake_triggers; creating an agent accepts the same optional fields. A new name must pass the same rules as create, stay globally unique, and not match an operator in that guild. A generating agent, or one whose guild is being deleted, cannot be renamed (409). Host notes folders that still use the name move with it; artifact paths stay on the id. The guild header stacks member avatars; a click opens that agent's inspector. Avatars are UI only: they are not hydrated into the system prompt.

Create ​

Creating a guild or agent writes PostgreSQL. A new agent gets a task column (from the focus string when one was given, otherwise apps/orchestrator/src/prompts/task.md) and a memory artifact row. A new guild stores about, description, and max_agents (default 15) on the guild row. Later edits go through PUT /api/guilds/:id (name, about, description, max_agents, git_author_email, visibility, routines_enabled) and PUT /api/guilds/:id/group-chat (agent_message_limit). The Settings tab saves the name, about, description, max_agents, commit author email, visibility, routines, and the message limit. A new name must pass the same rules as create and stay unique in the organisation (409 otherwise). A guild being deleted, or one with a member generating, cannot be renamed (409). Host notes folders that still use the name move with it; artifact paths stay on the id. A new agent's group-chat cursor starts at the guild's current sequence, so creation does not replay old chat.

Deletion ​

Deletion is the lifecycle surface. archived_at columns exist and stay unused.

Deleting an agent refuses if that agent is generating. It destroys the sandbox, deletes the agent's collection grants (collection_access rows with that agent as subject), deletes every secret granted only to that agent, and deletes the agent row. PostgreSQL cascades that agent's runs, messages, secret grants, connections, scoped bindings, and agent-level artifacts; a secret the agent stored that reaches others stays, with no creator. The agent's usage counter goes with it; guild, organisation, and global totals stay. Authored group messages stay, with the agent-name snapshot; agent and source-run references become empty. The name may be reused.

Deleting a guild is an admin action. It refuses if a member is generating or the dispatcher is busy. It destroys every member sandbox, deletes the collection grants held by the guild and by its members, deletes every secret whose grants all name the guild or its members, and deletes the guild row. PostgreSQL cascades agents, runs, group history, operators, secret grants, connections, scoped bindings, guild issues, and guild-level artifacts. The guild's own tables are soft-deleted with their records; organisation collections and their records stay. The guild and member-agent usage counters go with it; organisation and global totals stay. Organisation-wide and unassigned secrets, secrets with a grant elsewhere, instance bindings, and the connector catalog stay. Names may be reused.

Free software under the GNU Affero General Public License, version 3 only.