Colony layout and configuration¶
Start here for where colony config lives, how .paseka/ relates to machine-local state, and what paseka init creates.
For adapters, run directories, worktrees, and package layout see Architecture overview.
1. Colony-centric model¶
| Concept | Location | Role |
|---|---|---|
| Colony | Git repo root | Source of truth for code, history, and shareable hive config |
| Apiary | Developer machine | Hosts Hive Runtime, NATS, and local adapter credentials |
| Bee | Config + runtime | A role (Scout, Guard, Builder…) bound to an adapter that drives an external agent |
The runtime never owns LLM logic. It launches external tools through
adapters — the Cursor Agent CLI (agent), the Pi CLI (pi),
Claude Code, OpenCode, and declared script commands — reads their
output, and publishes results to the NATS bus as contract events.
To run the apiary on a separate always-on host (containerized toolbelt + Queen Console, reuse an existing NATS), see Homelab deployment.
2. Two-tier configuration¶
Project-local: .paseka/ (in repo)¶
Version-controlled colony definition. Safe to commit; no secrets.
.paseka/
├── colony.yaml # colony manifest: bees, routes, defaults
├── profiles/ # optional committed config overlays (not created by init)
│ └── pi.yaml # shareable recipe: adapter remap, params, model_aliases
├── bees/ # per-bee adapter bindings and non-secret params
│ ├── scout.yaml
│ └── builder.yaml
├── prompts/ # prompt templates (committed); see §2.1
│ ├── _partials/ # shared snippets (JSON contract, tone, etc.)
│ ├── scout.md
│ └── builder.md
├── cues/ # Forage Cue ingress shortcuts (committed); see [cues](cues.md)
│ ├── feature.yaml
│ └── hotfix.yaml
├── .gitignore # ignores worktrees/, runs/, cache/, *.local.yaml
├── runs/ # gitignored — per-agent file IPC and trail comb (architecture overview; purge --runs wipes standing checkpoints)
│ └── <traceId>/
│ ├── trail-events.ndjson # the trail's own record — every domain event the colony published for it
│ ├── <agentId>/
│ │ ├── prompt.txt
│ │ ├── system.txt # optional — rendered system_template
│ │ ├── summary.md
│ │ ├── meta.json
│ │ └── status.json
│ └── tasks/
│ └── <taskId>/
│ ├── task.md
│ └── runs.ndjson
│ └── proposals/ # proposal patches — runtime-owned code history (not a comb)
│ ├── <agentId>.patch # the diff the collector returned at finalization
│ └── <agentId>.json # sidecar metadata + publication state
└── worktrees/ # gitignored — isolated mutation workspaces
└── <traceId>/
colony.yaml — colony identity, default branch, bee registry, optional sectors (module/subfolder workspace scopes), NATS subject prefixes (optional overrides), colony-wide defaults including per-trace honey reserve (defaults.energy_budget, default 12), optional defaults.delivery (local_merge or pull_request; see pull-request delivery), optional model_aliases (stable names → vendor model ids for params.model; see spec 019), and optional auto_invites (HITL choreography that publishes session.invite when bus events match — see bee routing). Do not put profile: here — a sticky overlay belongs only in home config.yaml.
defaults:
prompt_template: default.md
system_template: default-system.md # optional colony-wide role context
energy_budget: 12
default_bee: builder # task role when task.bee is omitted
# delivery: pull_request # isolated trails land as origin PRs; default is local_merge
model_aliases:
small: composer-2.5
medium: cursor-grok-4.6-medium
high: cursor-grok-4.6-high-fast
Each traceId shares one Honey Reserve (energyToken): every adapter dispatch (task.ready and direct routing) consumes one token. When the reserve is empty, tasks move to blocked with summary Honey reserve exhausted. Beekeepers can top up a live tick via paseka energy add --trace <id> --amount <n>. Per-cue initial reserve overrides on fresh trails; standing cues then replace remaining each tick from standing.stipend: Forage Cues § Honey.
Example sectors for monorepos or git-submodule layouts:
A sector is a named path inside the colony. Tasks may optionally set sector; bees may declare a default sector in bees/*.yaml. Runtime resolves the adapter workspace as colonyRoot/<sector.path> or .paseka/worktrees/<traceId>/<sector.path> when worktree: true. The colony root remains the audit boundary for .paseka/runs/.
bees/*.yaml — one file per role: binds the bee to an adapter, prompt template(s), optional command / post_exec, sector/worktree, and routing rules. Full schema, examples, and variable substitution: bee config. Event routing (subscribes / publishes): bee routing. Project-local overrides that must not be committed live in *.local.yaml (gitignored).
2.1 Prompt templates¶
Templates live in .paseka/prompts/ — version-controlled, one colony, shareable across machines. Each bee may reference one or two templates from its bees/<role>.yaml:
| Field | Artifact | Role |
|---|---|---|
system_template (optional) |
system.txt |
Standing role context — injected by the adapter, not the first chat turn |
prompt_template |
prompt.txt |
User/task turn for AFK runs; optional kickoff for interactive chat |
When system_template is unset, behavior matches the previous single-template model (full prompt as positional argv only). Full variable list, partials, and override precedence: prompt templates. Bee YAML schema: bee config.
Bee config → templates:
# .paseka/bees/builder.yaml
role: builder
adapter: cursor
system_template: builder-system.md # optional — role / standing instructions
prompt_template: builder.md # user/task turn
worktree: true
Rendering: Go text/template at dispatch time. Runtime builds a PromptContext from bus event + colony state, writes prompt.txt (and system.txt when system_template is set) under .paseka/runs/<traceId>/<agentId>/, then passes rendered strings to the adapter.
Colony-wide fallbacks when a bee omits a field: defaults.prompt_template and optional defaults.system_template in colony.yaml.
Do not store prompts in ~/.config/paseka/ — they belong to the colony and should ride with the repo. Home config only holds secrets and runtime state.
Bee Language vs technical: UI/docs may say «Scout Bee»; templates can use bee tone for HITL readability. Bus payloads and JSON partials stay technical (SIGNAL, traceId, etc.) — see glossary.
Machine-local: ~/.config/paseka/<project-slug>/¶
Per-colony state on this machine. Not committed.
~/.config/paseka/<project-slug>/
├── config.yaml # secrets refs, NATS URL, adapter env (overridable via PASEKA_NATS_URL)
│ # optional model_aliases — overlays colony.yaml keys on this machine
│ # optional profile: <name> — sticky overlay for this machine only
│ # optional forge.command — argv for PR hosting (tea/gh script; not a bee adapter)
├── profiles/<name>/ # optional machine-local overlay for that name
│ ├── config.yaml # nats + model_aliases only
│ └── adapters/*.yaml # binary / api_key_env overlays
├── state.json # runtime: active worktrees, last traceId, hive status
├── telegram.yaml # optional: Telegram Human Gateway (not created by init)
├── telegram-notify-state.json # optional: gate notify dedup (runtime)
├── adapters/ # adapter-specific local overrides
│ ├── cursor.yaml # CLI binary path, API key env
│ ├── pi.yaml # Pi CLI binary path, API key env
│ ├── claude.yaml # Claude Code CLI binary, optional API key env
│ └── opencode.yaml # OpenCode CLI binary
Telegram bot tokens and allowlists stay machine-local — see Telegram gateway.
Common environment overrides:
| Variable | Purpose |
|---|---|
PASEKA_NATS_URL |
Overrides machine-local nats.url for CLI, runtime, Console, and gateways |
PASEKA_PROFILE |
Selects a config profile when --profile / --no-profile are omitted |
CURSOR_API_KEY |
Cursor Agent CLI authentication when not using agent login |
Adapter api_key_env target |
Vendor key named by adapters/<adapter>.yaml, for example GEMINI_API_KEY |
PASEKA_TRACE_ID, PASEKA_AGENT_ID, PASEKA_TASK_ID |
Injected into declared script adapter processes |
Split rule:
| Kind | Project .paseka/ |
Home ~/.config/paseka/<slug>/ |
|---|---|---|
| Bee roles & adapter choice | yes | — |
| Config profile recipes | yes (.paseka/profiles/<name>.yaml) |
yes (profiles/<name>/, sticky profile:) |
Model alias map (model_aliases) |
yes (base) | yes (overlay same keys) |
| Prompt templates (shareable) | yes | — |
| API keys, tokens | — | yes (or env var refs) |
| NATS connection override | — | yes |
Isolated trail delivery (defaults.delivery) |
yes | — |
Forge CLI argv (forge.command) |
— | yes (tokens stay in tea/gh login) |
| Active worktrees registry | pointer only | authoritative state |
| Published PR identity | — | state.json pullRequests[] |
| Active agent runs registry | pointer only | optional mirror in state.json |
| Event replay cache | — | yes |
A profile is an optional named overlay for the whole Queen Shell process (paseka --profile pi, PASEKA_PROFILE, or sticky profile: in home config.yaml). --no-profile ignores sticky. Unknown names fail closed and list what exists on both layers. paseka init does not create profiles; Nuc does not pack .paseka/profiles/. Global adapter: replaces LLM bees without command:; script and custom argv stay committed unless bees.<role>.adapter is set. Details: Bee config, CLI.
3. Project slug¶
Stable identifier for the home config directory.
- If
originremote exists → canonical slug from host/path (e.g.github.com-acme-api→acme-api, or fullgithub-com-acme-api). - Else → sanitized directory name of repo root (e.g.
paseka). - Collision on same machine → suffix with short hash of absolute repo path.
Stored in .paseka/colony.yaml as slug after first paseka init so later commands resolve the same home path.
4. paseka init¶
Run from inside a git repository (or at repo root).
paseka init [--adapter cursor|pi|opencode]
│
├─► resolve git root (fail if not a repo)
├─► compute / persist project slug
├─► create .paseka/colony.yaml (defaults)
├─► create .paseka/prompts/ with starter templates (scout, builder, hivewright)
├─► create .paseka/bees/ with starter bees (scout, builder, hivewright) for the selected adapter
├─► create .paseka/cues/ with starter cues (feature, hotfix) when missing
├─► create .paseka/.gitignore (worktrees/, runs/, *.local.yaml, cache/)
├─► create ~/.config/paseka/<slug>/config.yaml
├─► create ~/.config/paseka/<slug>/state.json (empty)
├─► create adapter config stubs (cursor, pi, claude, opencode)
└─► print next steps (adapter-specific auth / CLI setup, then `paseka run`)
--adapter selects which LLM adapter the starter bees use (cursor by
default; pi and opencode are supported scaffold choices). Unknown adapter
names fall back to cursor. Claude and script adapters can be selected later
in individual bee YAML.
paseka init is idempotent: existing files are preserved; missing pieces are added.
5. First local run¶
The choreographic runtime requires NATS with JetStream. The repository
docker-compose.yml starts both NATS and a browser UI:
Ports are 4222 for NATS clients, 8222 for NATS monitoring, and 31311
for the optional UI. Data is persisted in Docker volumes.
Then initialize and verify the colony:
For Pi or OpenCode, pass the corresponding --adapter during init and
authenticate that CLI. paseka bee run and paseka bee chat can launch
one-off work without the reactor; commands that publish or project
choreography events still need NATS. See the
CLI NATS dependency matrix.