Skip to content

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):

  1. Role must be non-empty and must not contain / or ...
  2. Base file is .paseka/bees/<role>.yaml (filename stem = role when role: is omitted).
  3. Event rules, run_summary, and adapter requirements are validated at load time.
  4. If <role>.local.yaml exists, its prompt_template and system_template override the base at resolve time (see prompt templates). Profiles do not overlay prompts, routing, command:, or post_exec — *.local.yaml stays 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 from colony.yaml sectors. Effective sector = task sector if set, else bee default (EffectiveSector). Workspace becomes colonyRoot/<sector.path> or worktree + sector path when worktree: 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) or direct (reactor runs the bee on the event).
  • Empty subscribes → any task.ready dispatch allowed.
  • publishes is advisory in MVP.
  • Declaring VERIFICATION/task.completed marks the AFK commit gate: when another bee explicitly publishes an isolated MUTATION/code.proposal with a diff, runtime defers auto-complete until that commit-gate bee emits task.completed. Root proposals do not open this defer.
  • Declaring MUTATION/code.proposal.isolated (or alias code.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.root on a worktree: false bee (typically hivewright) publishes from colony root; main-guard reviews on the same disk.
  • Do not subscribe to INSIGHT/pr.body with dispatch: direct. Pull-request copy is operational metadata; hosting is home forge.command, not a bee adapter. See pull-request delivery.

11. Prompt template resolution

Precedence (highest wins), from prompt templates:

  1. Inline prompt: / CLI --prompt
  2. bees/<role>.local.yaml → prompt_template
  3. bees/<role>.yaml → prompt_template
  4. colony.yaml → defaults.prompt_template

Do not store prompts in ~/.config/paseka/.