Manifest reference
Every beeuni.yaml v2 key, with defaults, limits, and validation rules.
The manifest is the file the platform treats as authoritative for a project. This page lists every beeuni.yaml (v2) key, its type, its default, and how the platform validates it. For the plain-language version, see Your project.
Two configuration surfaces
A Beeuni project has two configuration surfaces with strict, non-overlapping ownership.
- Beeuni config —
beeuni.yamlat the repo root defines the project environment, agents, tools, connectors, and triggers. Sandbox templates can reference a custom Dockerfile. - Agent config — the agent files, skills, and harness files. The agent harness reads this, in the sandbox and locally.
| Path | What it holds |
|---|---|
beeuni.yaml |
The manifest: agents and what each may access, triggers, connectors, env, sandbox templates. |
agents/<name>.md |
One agent: frontmatter and system prompt. agents.<name>.file names it. |
skills/<name>/SKILL.md |
One skill. Every harness loads it. |
memory/ |
The project memory. |
tools/<name>.ts |
Project tools, one module each. tools: declares them; every harness runs them. See Tools. |
harnesses/opencode/ |
Files only the default runtime reads: opencode.jsonc, plugins/, tools/, commands/. opencode.config_dir points here. |
Projects created before 2026-09 keep agents and skills under .beeuni/opencode/ and memory under .beeuni/memory/. Beeuni reads both layouts.
The join between the two halves is the agent’s .md file. A manifest key agents.<name> governs the file that agents.<name>.file names, or agents/<name>.md when file is omitted. Every behavioral field lives only in that .md file’s frontmatter and body, never in beeuni.yaml:
- system prompt
model,modetemperature,top_psteps,permission
The manifest’s agents: block sets governance only: which agents may launch, and what each one may touch. The validator enforces this. It rejects a v2 agent block that contains any behavioral field, with an error that points at the agent’s own .md file.
Location and versions
Any repo with a valid manifest at its root is a Beeuni project. beeuni.yaml (v2, YAML only) is the current format for new projects, created by the web “Create project” flow and by beeuni init. beeuni.toml (v1) still works for existing projects, but the platform accepts no new v2 features on it. See Legacy TOML for the v1 schema and the v1-to-v2 migration steps.
beeuni_version: 2 requires YAML — a .toml file that declares beeuni_version: 2 fails validation. A manifest that declares a version higher than 2 is rejected outright, so the platform never silently misreads a future field. Unknown top-level keys are ignored, so you can park your own metadata in the file.
validateManifest() is the single gate behind beeuni ship, the change request merge check, and beeuni validate. The same rules apply everywhere, so anything that merges into main is structurally sound. The schema is public and generated from the same package:
beeuni.v2.schema.jsonbeeuni.v1.schema.jsonbeeuni.schema.json(dispatches onbeeuni_version)
Point a beeuni.yaml at the v2 schema for editor validation, or fetch it from the CLI:
# yaml-language-server: $schema=https://beeuni.ai/schema/beeuni.v2.schema.json
beeuni_version: 2
beeuni schema --version 2
Full example
beeuni_version: 2
default_agent: beeuni
project:
name: my-project
description: What this project is.
env:
required: [DATABASE_URL]
optional: [STRIPE_API_KEY, WEBHOOK_SLACK_SECRET]
sandbox:
templates:
- slug: ml
name: ML Development
dockerfile: Dockerfile.ml
cpu: 4
memory: 16
opencode:
config_dir: harnesses/opencode
agents:
beeuni:
file: agents/beeuni.md
connectors: all
secrets: all
beeuni_permissions: all
skills: all
release-bot:
file: agents/release-bot.md
sandbox: ml
connectors: [github]
beeuni_permissions: [project.gitops.push]
secrets: [GITHUB_AGENT_TOKEN]
triggers:
- slug: daily-digest
type: cron
agent: beeuni
cron: '0 0 9 * * 1-5'
timezone: America/Los_Angeles
prompt: |
Summarize yesterday's commits. Open a CR against main.
Top-level keys
| Key | Required | Notes |
|---|---|---|
beeuni_version |
yes | must be 2 |
default_agent |
yes | must name a declared, enabled agent |
imports |
no | other YAML files or directories whose triggers, connectors, agents, apps, and tools merge into this manifest. See imports: |
tools |
no | the tools every session gets: tool name → repo-relative module path, or beeuni:<name> for a Beeuni tool. With a tools key, sessions get only the Beeuni tools it lists. Every harness runs them. See tools: |
runtime |
no | "opencode" (the default) or "pi" — the agent harness a session boots inside its sandbox; pi reads the same agent .md files and skills. The project’s pi_harness feature flag selects experimental runtime without this line. The experimental runtime needs the llm_gateway flag; without it the session boots default runtime. |
harnesses.pi.packages |
no | Extension packages the project’s experimental runtime sessions load. See harnesses: |
pi.config_dir |
no | harnesses/pi, then .beeuni/pi if present. extension runtime settings.json, extensions/, skills/, and prompts/. |
project.name / project.description |
no | display metadata; the platform does not read project.name for the project’s display name |
env.required / env.optional |
no | env var names; required is advisory only, never enforced at session start |
sandbox / sandbox.templates / sandbox.default |
no | sandbox image(s) and hardware |
opencode.config_dir |
no | default harnesses/opencode, then the legacy .beeuni/opencode |
triggers |
no | list of cron, webhook, and monitor triggers |
connectors |
no | list of connector definitions |
policy.default_mode |
no | allow_all (default) or risk; project-wide connector approval mode |
agents |
yes | name-to-block governance map; must not be empty. With imports, the map may live in an imported file |
imports:
Split one manifest across several YAML files. Use it when beeuni.yaml outgrows one screen: 30 triggers with multi-line prompts, a connector per team, one file per agent group.
# beeuni.yaml
beeuni_version: 2
default_agent: beeuni
imports:
- triggers/ # a directory: every .yaml and .yml file below it
- agents.yaml # a single file
agents:
beeuni:
connectors: all
beeuni.yaml
agents.yaml
triggers/
reports/
weekly.yaml
monthly.yaml
dockets/
freedom-forever.yaml
# triggers/reports/weekly.yaml
triggers:
- slug: weekly-report
name: Cross-Sector Weekly Report
type: cron
agent: galileo
cron: "0 15 * * 0"
prompt: |-
Build the weekly report.
The root file and its imports form one project configuration. A trigger in one file can name an agent declared in another.
Rules
- A path is relative to the repository root.
.., absolute paths, and globs are rejected. - A directory import takes every
.yamland.ymlfile below it, at any depth, sorted by path. Other files are skipped. - An imported file declares
triggers,connectors,agents,apps,tools, andimports. Every other key (beeuni_version,default_agent,runtime,project,env,opencode,sandbox,policy,policies) stays in the root file. An imported file that sets one fails validation. - An imported file can import more files. The limit is 8 levels and 200 files. A cycle is an error. A file reached twice merges once.
- One name, one file. A trigger slug, connector slug, agent name, app name, or tool name declared in two files is an error that names both files. Nothing overrides silently.
- Entries merge in order: the importing file first, then its imports in the order listed.
A broken import fails the whole manifest, the same way a YAML syntax error does. beeuni validate, beeuni ship, and the change request merge check all report it before it reaches main:
imports: triggers "weekly-report" is declared in both triggers/a.yaml and triggers/b.yaml — one name, one file
Edits go to the file that declares the entry. When the dashboard, the API, or beeuni triggers enable|disable|rm changes a trigger, connector, agent, or app that an imported file declares, only that file is written. The root file is not rewritten. A new entry is written to the root file. Move it into an imported file by hand if you want it there.
imports requires beeuni.yaml. A beeuni.toml manifest ignores the key.
tools:
The tools a session gets, by name. A value is one of two forms:
| Form | Meaning |
|---|---|
beeuni:<name> |
A Beeuni tool (web_search, image_search, scrape_webpage, memory, show), maintained by Beeuni. The key must be <name>. |
| A repo-relative module path | A tool of the project’s own, in any folder. Under a Beeuni tool name, the module replaces the Beeuni tool. |
tools:
web_search: beeuni:web_search
image_search: beeuni:image_search
scrape_webpage: beeuni:scrape_webpage
memory: tools/memory.ts # replaces the Beeuni memory tool
lookup_order: tools/lookup_order.ts
crm_note: integrations/crm/note.ts
The default runtime and experimental runtime run the same module. The module contract, beeuni tools ls,
beeuni tools eject, and the migration from harnesses/opencode/tools/ are in
Tools.
Selection rule.
- No
toolskey, in the root file or in any imported file: sessions get all five Beeuni tools. Every project created before the list existed keeps them. - A
toolskey, even an empty one (tools: {}, ortools:with every line deleted): sessions get only the Beeuni tools it lists, asbeeuni:<name>or as a module path. Atoolskey in an imported file counts.
Delete a beeuni:<name> line to remove that tool from every agent. Use
agents.<name>.tools to limit one
agent.
Errors.
-
A name is snake_case:
^[a-z][a-z0-9_]{0,63}$. -
A harness tool name (
bash,read,write,edit,apply_patch,glob,grep,list,task,question,todowrite,webfetch,websearch,skill,lsp,invalid,execute,plan_exit,pty_*) is an error. -
A path ends in
.ts,.js,.mts,.mjs,.cts, or.cjs. It must not start with/or-, or contain a.or..segment. -
beeuni:<name>under another key is an error. Under a Beeuni tool name, for exampleweb_search: beeuni:image_search:tools.web_search: must be `beeuni:web_search` (the Beeuni tool) or a repo-relative path to a .ts or .js module (e.g. `tools/web_search.ts`) that replaces it. -
beeuni:<name>for a name that is not a Beeuni tool, for exampleweb_serch: beeuni:web_serch:tools.web_serch: must be a repo-relative path to a .ts or .js module (e.g. `tools/web_serch.ts`). `beeuni:<name>` names a Beeuni tool under its own name: `web_search: beeuni:web_search`, `image_search: beeuni:image_search`, `scrape_webpage: beeuni:scrape_webpage`, `memory: beeuni:memory`, `show: beeuni:show`. -
beeuni validatealso reports a declared module that does not exist. Abeeuni:value needs no file.
Warnings. A warning never fails beeuni validate.
-
A
toolskey that lists none of the five Beeuni tools:tools: Sessions of this project get no Beeuni tool (web_search, image_search, scrape_webpage, memory, show). Add `<name>: beeuni:<name>` to keep one.It catches a project that adds its first own tool and drops the five by accident.
-
An agent’s
toolsthat names a Beeuni tool the project does not load:agents.beeuni.tools: "show" is a Beeuni tool this project does not load: add `show: beeuni:show` under the top-level `tools`, or remove it here.
project:
Optional, human-facing metadata: name and description. The platform does not read this table for anything — a project’s display name comes from its own database record. Treat it as documentation for people reading the repo.
env:
Declares the env var names your sessions need. Values live in the dashboard’s Environment variables page, never inline in the manifest. The platform decrypts and injects them as plain env vars at session start.
env:
required: [DATABASE_URL]
optional: [STRIPE_API_KEY]
| Field | Type | Notes |
|---|---|---|
required |
string[] |
Advisory. The dashboard prompts the user for these, but session start does not block on a missing value. |
optional |
string[] |
Available to sessions if set. Absence is fine. |
Env var names match ^[A-Z_][A-Z0-9_]*$. The Secrets Manager caps a name at 64 characters — a longer name parses here but can never get a value. Names starting with BEEUNI_ can never get a value either. Keep names at 64 characters or fewer, and avoid the BEEUNI_ prefix. Full contract: Secrets.
sandbox: and sandbox.templates
A list of named, bootable sandbox images. Optional — with no entries, every session boots the platform’s default image. Each template needs exactly one of dockerfile (repo-relative) or image (a public Docker reference, tag- or digest-pinned).
sandbox:
templates:
- slug: ml
name: ML Development
dockerfile: Dockerfile.ml
cpu: 4
memory: 16
disk: 50
| Field | Type | Default | Notes |
|---|---|---|---|
slug |
string | — | Required. Unique per project. default is reserved. |
name |
string | slug | Display label in the dashboard picker. |
dockerfile |
string | — | Repo-relative path. Mutually exclusive with image. |
image |
string | — | Public Docker image, tag- or digest-pinned. Mutually exclusive with dockerfile. |
entrypoint |
string | runtime layer’s own | Overrides the container entrypoint. |
cpu |
int | provider default | vCPU cores. Bound: 1–32. |
memory |
int | provider default | RAM in GiB. Bound: 1–128. |
disk |
int | provider default | Disk in GiB. Bound: 1–500. |
container_runtime |
bool | false |
Run Docker in the sandbox with bridge + overlay networking. See Runtime. |
Each value must be a positive integer. A value below the minimum fails validation with an error. A value above the maximum passes with a warning, then clamps at runtime. GPUs are not supported — declaring gpu produces a warning, not an error. See Runtime for what the runtime layer injects on top of your image.
sandbox.default
Set default on sandbox to make one template the project-wide default. Every session, trigger, and channel then boots it without naming a slug.
sandbox:
default: dev
templates:
- slug: dev
dockerfile: Dockerfile.dev
default must name a template declared in this manifest, or the reserved value "default" for the platform image.
An agent can select its environment with agents.<name>.sandbox. The value must name a manifest or dashboard template, or "default".
agents:
researcher:
sandbox: ml
Session template resolution uses this order:
- Explicit session
sandbox_slug. - Selected agent
sandbox. - Project
sandbox.default. - Platform
"default".
Cron triggers, webhook triggers, schedules, and channels use the selected agent’s template.
A spec change (cpu, memory, disk, container_runtime, or the image itself) rebuilds the project’s snapshot. The new size applies on the next session, not a running one.
opencode:
Where the default runtime config directory lives. Optional, with a default.
opencode:
config_dir: harnesses/opencode
| Field | Type | Default | Notes |
|---|---|---|---|
config_dir |
string | harnesses/opencode, then .beeuni/opencode |
Repo-relative directory. |
When config_dir is not set, Beeuni uses the first of harnesses/opencode and .beeuni/opencode that holds an opencode.json or opencode.jsonc. That directory holds the files only the default runtime reads: opencode.jsonc, plugins/, tools/, and commands/. Agents and skills live at the repo root, in agents/ and skills/. opencode.jsonc stays the runtime registry for plugins, MCP servers, providers, and permissions — do not duplicate those settings in the manifest. See Agents.
harnesses:
Per-harness settings. pi.config_dir points to a repository-relative directory of extension runtime configuration (default: harnesses/pi, then .beeuni/pi). The directory is imported on the experimental runtime boot. pi.packages is separate: it installs packages from the manifest’s harnesses.pi.packages per agent. Today one package key exists: pi.packages, the experimental runtime packages every experimental runtime session of this project loads (runtime: pi, or the pi_harness flag). A package can include extensions (tools, hooks, commands), and the skills and prompts a package ships.
runtime: pi
harnesses:
pi:
packages:
- npm:pi-web-access@0.30.0 # pinned extension version
- source: npm:pi-mcp-adapter@2.36.0
extensions: ["extensions/*.ts"] # load only these files of the package
skills: [] # load none of its skills
- ./harnesses/pi/audit.ts # an extension file in this repository
| Entry form | Meaning |
|---|---|
npm:<name>@<x.y.z> |
An npm package at an exact version. A range or a missing version fails validation. |
./<path> |
An extension file or package directory in this repository. It may not leave the repository with ... |
{ source, extensions, skills, prompts, themes } |
The same source with the experimental runtime’s own include/exclude filters. An omitted filter loads everything; [] loads nothing. |
At most 20 entries. Git sources are rejected.
Per agent
An agent can add its own packages and drop top-level ones, under agents.<name>.harnesses:
harnesses:
pi:
packages: [npm:pi-web-access@0.30.0] # every agent
agents:
researcher:
harnesses:
pi:
packages: [npm:@juicesharp/rpiv-todo@2.11.0] # researcher only
reviewer:
harnesses:
pi:
exclude: [pi-web-access] # reviewer loads no web tools
- An agent’s packages are the top-level list, minus its
exclude, plus its ownpackages. - An agent entry for a package the top level also lists replaces the top-level entry for that agent (another version, or other filters).
excludelists package names (pi-web-access,@scope/name) or./paths as the top-level list writes them. It never takes a version.- Each distinct package list is built once. Agents with the same list share the build.
- Packages belong to the agent a session starts with. A subagent that another agent starts with the
tasktool uses the standard workspace tools only (bash,read,write,edit,glob,grep), not its own packages and not the parent’s; the parent’s extension hooks still apply to its calls. Start a session with that agent to use its packages.
How packages reach a session:
- Merging the change request that edits this list builds the packages once, for the sandbox platform, with install scripts off. Each extension is pre-built into one minified file. The build keeps the package’s other files, except the code that file already contains, type declarations, source maps, and the root README and CHANGELOG. Projects with the same list share the build.
- A new or restarted session downloads the build while its repository clones, and loads each extension directly. A session never runs
npm installor compiles a package. - A package that cannot be pre-built (for example, one whose
pi.extensionsuses globs) still works: the session loads it from the installed packages instead, which takes longer. If a package’s code reads one of the files the build leaves out, give its entry anextensionsfilter: the session then loads it from the installed packages too. - A session that starts before the build exists boots without the project packages and starts the build; the next session has them.
Beeuni also installs a set of system packages into every experimental runtime session. A project entry for the same package replaces the system version. A repository can also hold extension runtime extensions in .pi/extensions/*.ts; experimental runtime loads them without a manifest entry.
Extensions run without a terminal UI: tools, hooks, and commands work; terminal-only widgets do nothing.
triggers:
A list of cron, webhook, and monitor definitions. Each entry fires a session that runs prompt as its first message.
triggers:
- slug: daily-digest
type: cron
cron: '0 0 9 * * 1-5'
prompt: Summarize yesterday's commits.
| Field | Required | Default | Notes |
|---|---|---|---|
slug |
yes | — | [a-z0-9][a-z0-9_-]{0,127}, unique among triggers. |
type |
yes | — | cron, webhook, or monitor (experimental). |
prompt |
yes | — | Non-empty. Supports templating. |
name |
no | slug | Human label. |
agent |
no | default_agent |
Must name a key in agents:. Omit it to use default_agent; do not write the literal default. |
enabled |
no | true |
false skips the entry. |
model |
no | resolves at fire time | Wire form provider/model. Pins the fired session to that model. See Models. |
session_mode |
no | fresh |
fresh, reuse, pinned, or keyed. |
session_id |
required for pinned |
— | Exact session to re-prompt. |
Cron triggers need exactly one of cron (a 6-field expression) or run_at (a one-off ISO-8601 timestamp), plus timezone as an IANA name. Webhook triggers need secret_env, the name of a secret that uses broker delivery with the connector consumer. Monitor triggers need run (a repo-relative command) and mode (poll or stream), and reject every cron and webhook field. Full field reference, credential setup, payload templating, endpoints, and session strategy: see Triggers.
connectors:
A list of external tools an agent can call. The definition lives in git; credentials live in the platform, never in the manifest. See Connectors for the conceptual model.
connectors:
- slug: gmail-read
name: Gmail read only
provider: pipedream
app: gmail
authorization_strategy: user
policies:
- match: search_email
action: always_run
| Field | Required | Notes |
|---|---|---|
slug |
yes | [a-z0-9][a-z0-9_-]{0,127}, unique among connectors. |
provider |
yes | pipedream, mcp, openapi, postman, graphql, http, or channel. |
name |
no | Display name. Defaults to slug. |
authorization_strategy |
no | project or user. Defaults to project when omitted. A project strategy uses active project connections. A user strategy uses only the acting member’s connection. |
enabled |
no | Defaults to true. |
credential |
no | Only shared is supported. The retired per_user mode is a hard error. |
sensitive |
no | Defaults to false. true makes require_approval the unmatched-action default, including reads. Explicit project and connector rules still resolve first. |
Provider-specific fields:
| Provider | Required field | Notes |
|---|---|---|
pipedream |
app |
account optional, defaults to slug. |
mcp |
url |
transport: http (default) or sse. |
openapi |
spec |
A URL or repo-relative path. |
postman |
spec |
A Collection JSON URL or path, a .postman/api manifest, or a Postman workspace URL. |
graphql |
endpoint |
spec optional (SDL). |
http |
base_url |
spec optional. |
channel |
platform |
slack, teams, email, or voice. |
computer |
— | API-managed. You cannot declare it by hand. Each connected computer is one of its accounts. See Computers. |
channel connectors rarely need a hand-written entry — connecting a channel from the dashboard creates one for you. See Slack & channels. The slugs beeuni_slack, beeuni_teams, beeuni_email, and computer are platform-owned; using one with a different provider is a validation error. The computer connector is created when the first member connects a computer, because machine ids are account control-plane identities and must not enter the manifest.
connectors.auth: optional, for providers other than pipedream. type is bearer, basic, custom, api_key, oauth1, hmac, aws_sigv4, mtls, or none (default). oauth1 is restricted to openapi, postman, and http providers. in is header (default), query, or cookie. name is required when type is custom or api_key.
connectors.policies: a list of {match, action} pairs. match is a glob over
tool names. action is always_run, require_approval, or block. Policies
belong to the connector. Every connection under that connector uses the same
policies.
policy.default_mode: a top-level key, separate from connectors:, that sets the project-wide connector approval mode. It takes allow_all (default; every unmatched tool runs) or risk (require approval for write and destructive unmatched calls). Set it with beeuni connectors policy set --default <risk|allow_all> — see CLI.
Channels
v2 removes channels: from the schema. Channel-to-agent routing (Slack, Microsoft Teams, email, and voice today) is live operational state, not declarative config. You set it from the dashboard’s Channels page or from chat commands, the same boundary that keeps credentials out of git. Connecting a channel still creates a connectors entry with provider: channel for the agent to call. See Slack & channels. The v1 [[channels]] table is covered in Legacy TOML.
agents:
A name-to-block map, keyed by agent name. This map is governance only — it grants what an agent may touch, never what it says or does.
This block is the second of the two bindings: a principal gets roles from Beeuni, and an agent additionally carries the Beeuni permissions declared here. A session can only do what both allow. See One vocabulary, two bindings.
default_agent: beeuni
agents:
beeuni:
file: agents/beeuni.md
connectors: all
secrets: all
beeuni_permissions: all
skills: all
release-bot:
file: agents/release-bot.md
connectors: [github]
connectors_required: [github]
beeuni_permissions: [project.gitops.push]
secrets: [GITHUB_AGENT_TOKEN]
| Field | Default | Notes |
|---|---|---|
| (map key) | — | [a-z0-9][a-z0-9_-]{0,127}, unique per project. Without file, it is also the .md filename. |
file |
agents/<name>.md |
Repo-relative path of the agent’s .md. See The agent file. |
enabled |
true |
false treats the agent as undeclared — the platform will not launch it. |
connectors |
none |
Which connector slugs this agent may call. all means every connector. |
connectors_required |
none |
Deprecated: parsed and ignored. Nothing gates sandbox startup on a connector any more; a call to a connector with nothing connected returns connector_not_connected with a connect link. Must still be a subset of connectors when present. |
secrets |
none |
Which project secrets this agent receives as sandbox env vars. Renamed from v1’s env. |
beeuni_permissions |
none |
Which Beeuni permissions (project actions) this agent may exercise, through the CLI, the API, or git. all means every project permission, still capped by the agent’s ceiling role and never including the human-only permissions. beeuni_cli is the deprecated spelling: still accepted, with a validation warning; setting both to different values is an error. |
skills |
none |
Which skills this agent may load. |
apps |
none |
Which Beeuni App slugs this agent may open when the App is restricted or private. all means every App in the project. See Agents and Apps. |
tools |
all |
Which tools this agent may use: harness, Beeuni, and project tools. all, none, a list (only those), or { exclude: [...] } (all but those). The earlier map form { bash: false } still works. Unlike the grants above, an omitted tools means every tool. See Who may use which tool. |
repository_access |
true |
Whether new sessions receive the project repository. false disables repository delivery and repository access through session credentials. Existing sessions keep their saved policy. |
v2 is deny-by-default: an omitted connectors, secrets, beeuni_permissions, skills, or apps on a declared agent resolves to none. Grant every permission an agent needs explicitly, as the starter’s beeuni agent does above. A project migrating from v1 must re-grant everything by hand — v1 defaults env (secrets) to all when omitted, the opposite of v2.
connectors_personal remains a deprecated input alias for
connectors_required. New manifests must use connectors_required. The
connector’s authorization_strategy decides whether the authorization
is project-owned or member-owned.
beeuni_permissions grants come from a fixed set of project-scoped permissions (project.read, project.gitops.push, project.gitops.merge, project.gitops.ref.any, project.trigger.*, project.secret.*, project.connector.*, and more). Account-scoped permissions — member.*, billing.*, project.create — can never be granted to an agent. Run beeuni validate --scopes from inside a session to print the live, grantable list.
The agent file
agents.<name>.file names the agent’s .md, relative to the repo root.
agents:
support:
file: agents/support.md
- The path must end in
.md. - The path must not start with
/or-. It must not contain a.or..segment, or an empty segment. - Each segment uses only letters, digits,
_,-,., and spaces. - When
fileis omitted, Beeuni readsagents/<name>.md, then.beeuni/opencode/agents/<name>.md. Withopencode.config_dirset, the second path is<config_dir>/agents/<name>.md. - When the dashboard saves an agent that has a
.md, it writesfilewith that path. - The API refuses a request that changes
file(400, codeinvalid_config). To move an agent, move its.mdand updatefileinbeeuni.yamlin the same commit.
beeuni validate and the change request merge check reject an invalid file with an error on agents.<name>.file.
When config changes take effect
- A manifest,
agents/,skills/, or default runtime config directory edit applies only after a change request merges tomain. Sessions and triggers read the default branch, not session branches. - A trigger’s cron or webhook change is picked up by the scheduler within seconds of the merge.
- A sandbox image or hardware change rebuilds the snapshot. The new spec applies on the next session, not the current one.
- A secret value change in the dashboard resolves at sandbox-create time. It applies on the next session, not a running one.
Round-trip rules
Dashboard edits are a read-modify-write on the file that declares the entry: beeuni.yaml, or an imported file. To keep diffs clean across UI and in-session edits:
- Keep
beeuni_versionas the first key. - Inside a trigger entry, order fields
slug,name,type,agent,enabled, then type-specific fields, thenpromptlast. - If you add a webhook trigger before its secret is set, list the secret name in
env.optional. Leave the triggerenabled: falseuntil the value is in.
Repository access
Set agents.<name>.repository_access to false for agents that do not need project source files.
They can still create sandbox files and use their granted tools, secrets, and connectors.
Set it to true for agents that need the repository. Git permissions remain separate.
Change this setting in the agent editor under Workspace → Project repository access.
The setting applies to new sessions. Existing sessions keep their saved policy, including after runtime replacement.
agents:
support:
repository_access: false
engineer:
repository_access: true
The deprecated workspace field remains readable: branch means true, and runtime means false.
Legacy read configurations still reject session creation until you replace the field with an explicit boolean.
There is no read-only repository mode. Conflicting old and new fields are rejected.
The editor and SDK send repository_access. For disabled access, the API also stores workspace: runtime as a compatibility mirror. This preserves the restriction for older API replicas during rollout or rollback. API reads omit the mirror. Hand-authored manifests using only repository_access require the updated API.