Bee role config (.paseka/bees/<role>.yaml)¶
A bee is a named role bound to an adapter, prompt template, and optional routing / completion rules. Each file under .paseka/bees/ defines one role.
Implementation: internal/colony/bee.go (Bee struct, LoadBee), plus command.go, params.go, routing.go, run_summary.go, completion.go, bee_validate.go.
Related: bee routing (subscribes / publishes), prompt templates, architecture overview (adapters, colony layout), pull-request delivery (pr.body; forge is not an adapter).
1. Files and loading¶
.paseka/bees/
├── scout.yaml
├── builder.yaml
├── guard.yaml
└── builder.local.yaml # optional, gitignored overlay
| Path | Purpose |
|---|---|
.paseka/bees/<role>.yaml |
Canonical role definition (committed) |
.paseka/bees/<role>.local.yaml |
Machine-local overlay; prompt_template and system_template applied at resolve time |
paseka loads committed bees via colony.LoadBee(colonyRoot, role) / LoadAllBees (files on disk). Dispatch, doctor, status topology, reactor, and Console use the effective bee after a config profile is applied (see colony layout):
- Role must be non-empty and must not contain
/or... - Base file is
.paseka/bees/<role>.yaml(filename stem = role whenrole:is omitted). - Event rules,
run_summary, and adapter requirements are validated at load time. - If
<role>.local.yamlexists, itsprompt_templateandsystem_templateoverride the base at resolve time (see prompt templates). Profiles do not overlay prompts, routing,command:, orpost_exec—*.local.yamlstays prompt-only.
Trail export --include bees and Nuc pack the committed YAML files, not the overlayed view.
*.local.yaml files are listed in .paseka/.gitignore and are skipped by LoadAllBees.
2. Schema¶
Go type (internal/colony/bee.go):
type Bee struct {
Role string
Adapter string
PromptTemplate string
SystemTemplate string
Sector string
Worktree bool
Intents []string
DefaultIntent string
Command Command
PostExec Command
Params map[string]any
Subscribes []SubscriptionRule
Publishes []PublicationRule
CompletionContract CompletionContract
RunSummary RunSummaryPolicy
}
Field reference¶
| YAML field | Required | Meaning |
|---|---|---|
role |
recommended | Role name. If empty, defaults to the filename stem (builder.yaml → builder). |
adapter |
no | cursor (default), pi, claude, opencode, or script. Unknown names fail load. A process --profile with global adapter: replaces this for LLM bees that have no command:. |
prompt_template |
usually | Path relative to .paseka/prompts/. User/task turn. Optional for adapter: script (no colony default applied when omitted). |
system_template |
no | Path relative to .paseka/prompts/. Role / standing instructions injected by the adapter (see prompt templates). |
sector |
no | Default sector name from colony.yaml sectors. Task sector wins when set. |
worktree |
no | When true, adapter cwd is under .paseka/worktrees/<traceId>/ (plus sector path if any). |
intents |
no | Explicit intent vocabulary for this bee. When omitted, runtime discovers intents from _partials/<role>-intent-*.md prompt partials. |
default_intent |
no | Default intent when the caller omits --intent or passes an unknown value. When omitted, general is used if present in the vocabulary; otherwise the first discovered intent. |
params |
no | Adapter flag map (model, yolo, plan, reasoning, …). Mutually exclusive with command: a bee that sets command may only carry params that equal the adapter defaults; any non-default param fails load. |
command |
script: yes | Full agent argv (string or YAML list). Replaces params-based flag mapping. |
post_exec |
no | Hook after AFK bee run and interactive bee chat. Failures are logged; they do not fail the bee run. |
subscribes |
no | Event → dispatch rules. Empty = backward-compatible allow any task.ready. See bee routing. |
publishes |
no | Advisory expected outputs; undeclared domain publishes warn only (MVP). |
completion_contract |
no | Hard post-run event requirements; violation fails the run. |
run_summary |
no | auto (default) | required | disabled — controls INSIGHT/run.summary synthesis/enforcement. |
3. Example¶
# .paseka/bees/builder.yaml
role: builder
adapter: cursor
sector: frontend
params:
model: composer-2.5
yolo: true
# Optional: override adapter flag mapping (docker-compose style).
# command: agent -p --yolo --workspace $WORKSPACE $PROMPT
prompt_template: builder.md # relative to .paseka/prompts/
worktree: true # run inside .paseka/worktrees/<traceId>/
subscribes:
- type: SIGNAL
kind: task.ready
dispatch: task
publishes:
- type: MUTATION
kind: code.proposal.isolated
Guard with a completion contract:
# .paseka/bees/guard.yaml
role: guard
adapter: cursor
prompt_template: guard.md
params:
model: composer-2.5
yolo: true
worktree: true
subscribes:
- type: MUTATION
kind: code.proposal.isolated
dispatch: direct
publishes:
- type: VERIFICATION
kind: verification.success
- type: VERIFICATION
kind: verification.failed
completion_contract:
required:
- type: VERIFICATION
kind_one_of:
- verification.success
- verification.failed
count: 1
Hivewright and main-guard (root proposal path):
# .paseka/bees/hivewright.yaml
role: hivewright
adapter: cursor
worktree: false
publishes:
- type: MUTATION
kind: code.proposal.root
# .paseka/bees/main-guard.yaml
role: main-guard
adapter: cursor
worktree: false
subscribes:
- type: MUTATION
kind: code.proposal.root
dispatch: direct
publishes:
- type: VERIFICATION
kind: verification.success
- type: VERIFICATION
kind: verification.failed
4. Adapters¶
ResolveAdapter() defaults empty adapter to cursor. Allowed values: cursor, pi, claude, opencode, script.
| Adapter | Notes |
|---|---|
cursor |
Cursor Agent CLI (agent). Params map to CLI flags unless command is set. With system_template, runtime merges system + task into the positional prompt ($PROMPT); Pi/Claude use separate append-system flags instead; OpenCode also merges into one message. |
pi |
Pi CLI (pi). Params: model, reasoning, plan, binary (no yolo equivalent; paseka doctor warns when set). A vendor/model[:suffix] model is split at the first / into --provider <vendor> --model <rest>; the rest keeps inner slashes and colon suffixes. Output mode is runtime-owned (--mode json; text only under bee run --raw). Reports token usage on AFK result.json (--mode json events, else the run-scoped session file) and on interactive session.json. |
claude |
Claude Code CLI; same params plumbing as other LLM adapters. |
opencode |
OpenCode CLI (opencode). AFK opencode run; HITL TUI. Params: model (native provider/model), yolo → --auto, reasoning → --variant, plan → --agent plan, binary. Output format is runtime-owned (--format json; default only under bee run --raw). Auth via opencode auth login / env. Reports token usage from step_finish parts on AFK result.json, and from the provider's session totals on interactive session.json. |
script |
Requires command. AFK-only (bee run); bee chat is LLM-only. params ignored. prompt_template optional. |
Adapter drivers and flag mapping live in architecture overview §1. Machine-local credentials stay in ~/.config/paseka/<slug>/adapters/*.yaml.
Script bee example:
# .paseka/bees/oracle-guard.yaml
role: oracle-guard
adapter: script
command: ./scripts/oracle-guard.sh
run_summary: disabled
subscribes:
- type: MUTATION
kind: code.proposal.isolated
dispatch: direct
publishes:
- type: VERIFICATION
kind: verification.success
- type: VERIFICATION
kind: verification.failed
Script process env (in addition to command variable substitution): PASEKA_TRACE_ID, PASEKA_AGENT_ID, PASEKA_TASK_ID, PASEKA_WORKSPACE, PASEKA_COLONY_ROOT, PASEKA_RUN_DIR, PASEKA_BEE, PASEKA_EVENT_LOG, PASEKA_RESULT_FILE, PASEKA_PROMPT_FILE. Domain events still go through paseka event emit --stdin.
5. params¶
Mapped by LayerFromBee (internal/colony/params.go). Defaults: yolo: true.
| Key | Type | Used by |
|---|---|---|
model |
string | cursor, pi, claude, opencode — alias key from colony.yaml model_aliases or a full id: vendor/model[:suffix], or a bare id with no vendor |
yolo |
bool | cursor (--trust --force); claude (bypassPermissions); opencode AFK (--auto); pi has no equivalent (doctor warns) |
plan |
bool | cursor (--plan); pi (--plan); claude (plan); opencode (--agent plan). Wins over yolo: the read-only plan mode drops trust/force. |
binary |
string | override CLI binary name |
reasoning |
string | low | medium | high | passthrough — pi (--thinking); opencode (--variant); cursor and claude have no mapping (doctor warns) |
env |
map | declared pass-through environment for the child and its post_exec hook. Values are literals or host references (GITHUB_TOKEN: $HOST_GITHUB_TOKEN). The declared keys are redacted in adapter logs. |
env_mode |
string | strict opts into denying undeclared environment: the child keeps only process essentials (PATH, HOME, locale, PASEKA_*), declared env, and the injected credential. Default inherits the whole parent environment. |
timeout |
duration | AFK only, opt-in. Bounds the run (e.g. 90s, 5m), measured from launch: a timeout is enforced as SIGTERM, then SIGKILL after a short grace, and the run reports cancelled with reason timeout on status.json so a post-mortem can tell slow from stuck. Absent means unbounded (the default). Compatible with command: it is process control, not an adapter flag. Interactive bee chat sessions ignore it — the human is the timeout. |
Adapter output format is runtime-owned, not a bee param. The runtime always requests each adapter's structured mode (cursor --output-format stream-json, pi --mode json, claude --output-format stream-json --verbose, opencode run --format json) so it can parse usage, session ids, and summaries. paseka bee run --raw is a per-invocation debugging escape hatch that falls back to plain text and logs the runtime features it degrades (usage, session tracking, summary normalization); it is never committed to a bee file.
The launch plan assembles the child environment explicitly: the inherited environment, the adapter's resolved api_key_env credential (recorded on the plan so logs redact it), and params.env. post_exec receives that same plan environment, so a credential handed to a bee also reaches its post-run hook. paseka doctor warns when a machine-local adapter declares an api_key_env whose host variable is unset, so a credential that resolves empty is visible rather than mistaken for valid auth.
The legacy aliases trust, force, thinking, provider, and output_format are deprecated, not removed: they still load for one release, and paseka doctor names the replacement (trust/force → yolo, thinking → reasoning, provider → fold the vendor into model, output_format → runtime-owned). Removal is deferred to the next release; see the backlog.
When command is set, these params are not turned into CLI flags. command and non-default params are mutually exclusive and fail at load (paseka bee run/bee chat/init); params that equal the adapter defaults (e.g. yolo: true) are accepted as a no-op. adapter still selects result parsing, session PTY, and home-config credential injection.
Model aliases: bees may set params.model to a key from colony.yaml model_aliases (e.g. high) or to a full id (e.g. anthropic/claude-sonnet-4, or a bare composer-2.5). Alias values carry the vendor so switching a profile's model_aliases switches vendor for every bee on that alias. Runtime resolves aliases once at dispatch/session start, then maps the id per adapter (cursor/claude and opencode pass it through; pi splits the vendor into --provider/--model). Home config.yaml model_aliases overlays colony keys on this machine. Unknown names pass through unchanged. Per-bee exceptions stay in that bee's YAML; *.local.yaml does not override params. See colony layout and spec 019.
The resolved id is recorded per run on request.json as model (plus modelAlias for the alias key the bee declared), so a run's model stays readable after model_aliases, params, or the active profile change. The Console shows it on the run page and an export carries it in the run's block.
6. command and post_exec¶
Both accept a shell-like string or a YAML list of strings (colony.Command). String form is split into argv without invoking a shell (quotes supported; unclosed quotes error).
command: agent -p --trust --workspace $WORKSPACE $PROMPT
# or
command: ["agent", "-p", "--model", "composer-2.5", "$PROMPT"]
post_exec: notify.sh --bee builder --status ok --summary "$RESULT"
# or
post_exec: ["curl", "-fsS", "-d", "@$META", "https://hooks.example.com/paseka"]
Variable substitution¶
Supports $NAME and ${NAME}:
| Variable | When set | Value |
|---|---|---|
$PROMPT / ${PROMPT} |
dispatch + post_exec | rendered user/task prompt; for cursor, includes system_template when set (newline-separated) |
$SYSTEM_PROMPT / ${SYSTEM_PROMPT} |
dispatch + post_exec | rendered system prompt (still written to system.txt; not duplicated in Cursor positional when using default adapter mapping) |
$SYSTEM_FILE / ${SYSTEM_FILE} |
dispatch + post_exec | path to system.txt |
$CURSOR_PLUGIN / ${CURSOR_PLUGIN} |
dispatch + chat | deprecated — no longer materialized; $PROMPT carries merged system+task for Cursor |
$WORKSPACE / ${WORKSPACE} |
dispatch + post_exec | agent working directory |
$TRACE_ID / ${TRACE_ID} |
dispatch + post_exec | current flight trail |
$AGENT_ID / ${AGENT_ID} |
dispatch + post_exec | this invocation id |
$TASK_ID / ${TASK_ID} |
dispatch + post_exec | task id when dispatched from ledger |
$COLONY_ROOT / ${COLONY_ROOT} |
dispatch + post_exec | git repo root |
$RUN_DIR / ${RUN_DIR} |
dispatch + post_exec | .paseka/runs/<traceId>/<agentId>/ |
$RESULT_FILE / ${RESULT_FILE} |
dispatch + post_exec | path to summary.md |
$RESULT / ${RESULT} |
post_exec only | human-readable run summary text |
$META / ${META} |
post_exec only | path to meta.json |
${<NAME>} |
command dispatch | any name in the launch plan's assembled environment, so custom argv shares the child's conventions (e.g. PASEKA_RESULT_FILE, PASEKA_RUN_DIR for script, the injected credential for LLM adapters). A fixed variable of the same name above wins. |
7. Sector and worktree¶
sector— default named path fromcolony.yamlsectors. Effective sector = task sector if set, else bee default (EffectiveSector). Workspace becomescolonyRoot/<sector.path>or worktree + sector path whenworktree: true.worktree: true— mutations under.paseka/worktrees/<traceId>/; audit I/O stays in.paseka/runs/.worktree: false— adapter cwd is colony root (+ sector). Used for hivewright / main-guard root proposals.
Worktree ↔ proposal kind invariants (hard)¶
Auto-synthesis and paseka doctor enforce matching worktree and declared publish/subscribe kinds:
Bee worktree |
Declares publish | Auto-publish kind | Else |
|---|---|---|---|
true |
isolated or alias code.proposal |
code.proposal.isolated |
Skip auto mutation + warn |
false |
code.proposal.root |
code.proposal.root |
Skip + warn |
true |
only root |
— | Skip + doctor error |
false |
only isolated / alias |
— | Skip + doctor error |
Subscriber mismatches (guard with worktree: false, main-guard with worktree: true) are doctor errors. Bare code.proposal alias use is a doctor warning. review: final on a task whose bee publishes code.proposal.root is rejected at task.plan load.
Fail closed: empty / missing publishes must not auto-publish mutations.
An auto-published proposal is archived as a patch under .paseka/runs/<traceId>/proposals/ and the MUTATION carries a colony-root-relative ref instead of an inline diff. This is runtime-owned: a bee declares the kind and nothing else, and it never sees or writes the store. A bee that emits its own MUTATION (with an inline diff) is passed through unchanged and gets no automatic patch conversion. See Spec 039.
Colony sector definitions remain in architecture overview.
8. run_summary¶
Controls runtime handling of INSIGHT/run.summary:
| Value | Behavior |
|---|---|
auto (default / empty) |
Runtime may synthesize a summary when missing and policy allows |
required |
Run fails if no summary event is present after the adapter exits |
disabled |
No synthesis; useful for script / oracle bees |
Invalid values fail bee load. See also bee routing §5 and insight kinds.
9. completion_contract¶
Hard requirements checked against events.ndjson after the adapter exits. Violation → run failed even if the process exit code was zero.
completion_contract:
required:
- type: VERIFICATION
kind_one_of:
- verification.success
- verification.failed
count: 1 # default 1; must match exactly that count among allowed kinds
| Field | Meaning |
|---|---|
type |
Domain event type (SIGNAL, INSIGHT, MUTATION, VERIFICATION) |
kind_one_of |
Allowed payload.kind values (required, non-empty) |
count |
Exact match count among those kinds (default 1) |
Narrative INSIGHTs do not satisfy contracts unless listed. Full routing semantics: bee routing §6.
10. Routing fields (subscribes / publishes)¶
Documented in bee routing. Summary:
subscribes[].dispatch:task(task-ledger) ordirect(reactor runs the bee on the event).- Empty
subscribes→ anytask.readydispatch allowed. publishesis advisory in MVP.- Declaring
VERIFICATION/task.completedmarks the AFK commit gate: when another bee explicitly publishes an isolatedMUTATION/code.proposalwith a diff, runtime defers auto-complete until that commit-gate bee emitstask.completed. Root proposals do not open this defer. - Declaring
MUTATION/code.proposal.isolated(or aliascode.proposal) on the dispatched bee (typically builder) is what opens the isolated defer path when a commit-gate publisher exists in the colony. - Declaring
MUTATION/code.proposal.rooton aworktree: falsebee (typically hivewright) publishes from colony root;main-guardreviews on the same disk. - Do not subscribe to
INSIGHT/pr.bodywithdispatch: direct. Pull-request copy is operational metadata; hosting is homeforge.command, not a bee adapter. See pull-request delivery.
11. Prompt template resolution¶
Precedence (highest wins), from prompt templates:
- Inline
prompt:/ CLI--prompt bees/<role>.local.yaml→prompt_templatebees/<role>.yaml→prompt_templatecolony.yaml→defaults.prompt_template
Do not store prompts in ~/.config/paseka/.