Prompt templates¶
Paseka renders bee prompts from version-controlled Markdown files under .paseka/prompts/. Templates use Go text/template syntax. At dispatch time the runtime fills in context variables, writes the result to .paseka/runs/<traceId>/<agentId>/prompt.txt (and optionally system.txt), and passes rendered strings to the adapter.
Implementation: internal/prompts.
1. Directory layout¶
.paseka/prompts/
├── _partials/ # shared snippets (not used as top-level bee templates)
│ ├── emit-howto.md
│ ├── emit-insight.md
│ ├── emit-signal.md
│ ├── emit-verification.md
│ └── emit-task-completed.md
├── default.md # colony-wide fallback
├── scout.md
└── builder.md
| Path | Role |
|---|---|
.paseka/prompts/*.md |
Bee prompt templates |
.paseka/prompts/_partials/*.md |
Reusable partials included via {{template "name" .}} |
~/.config/paseka/<slug>/ |
No prompts — secrets and machine-local state only |
Prompts belong in the git repo so the colony shares the same instructions across machines.
2. Linking a template to a bee¶
Each bee references template files (relative to .paseka/prompts/) in its config:
# .paseka/bees/scout.yaml
role: scout
adapter: pi
system_template: scout-system.md # role / standing instructions (optional)
prompt_template: scout.md # user/task turn
worktree: true
| Field | Artifact | Role |
|---|---|---|
system_template (optional) |
system.txt |
Identity and standing instructions — injected by the adapter, not shown as the first chat turn |
prompt_template |
prompt.txt |
User/task message for AFK runs; optional kickoff for interactive chat |
Colony-wide fallbacks when a bee omits a field:
# .paseka/colony.yaml
defaults:
prompt_template: default.md
system_template: default-system.md # optional
When system_template is unset, behavior matches the previous single-template model (full prompt as positional argv only).
3. Supported variables¶
The runtime passes a single context object (prompts.Context) to every template. In templates, reference fields as {{.FieldName}}.
| Variable | Type | Description |
|---|---|---|
{{.Bee}} |
string |
Bee role from bees/<role>.yaml (e.g. scout, builder). |
{{.TraceID}} |
string |
Flight trail id for the current task chain. From --trace or generated by runtime. |
{{.TraceTitle}} |
string |
Resolved human Flight Trail title. From latest INSIGHT/trace.title, then feature.requested title, then first task title; empty when unresolved. |
{{.AgentID}} |
string |
Unique id for this agent invocation. Generated per run. |
{{.TaskID}} |
string |
Optional task id within the trace. From DispatchRequest.TaskID when dispatching a queued subtask. |
{{.ColonyRoot}} |
string |
Absolute path to the git repository root. |
{{.Workspace}} |
string |
Absolute cwd for the adapter: colony root, or .paseka/worktrees/<traceId>/ when worktree: true. |
{{.Task}} |
string |
Task body (nectar). From CLI --body, Queen Console session launch, or bus event payload. |
{{.Intent}} |
string |
Normalized task intent for partial routing within the bee's vocabulary. Empty or unknown caller input becomes the bee's default intent. |
{{.IntentRaw}} |
string |
Caller-supplied intent before normalization (CLI --intent, task ledger, or bus payload). |
{{.Insights}} |
[]string |
Narrative INSIGHT strings projected from prior runs on the trace. See insight kinds. |
{{.ResultFile}} |
string |
Absolute path to the human-readable summary.md log for this run under .paseka/runs/<traceId>/<agentId>/. |
{{.Interactive}} |
bool |
true for interactive paseka bee chat sessions; false for AFK dispatch. |
{{.IsLastWorkTask}} |
bool |
true at AFK ledger task dispatch when the current task is the sole incomplete non-final work task; false for chat, ad-hoc bee run, and all other paths. Gates must-emit trace.summary guidance in emit partials. |
{{.Adapter}} |
string |
Resolved adapter name (cursor, pi, claude, script). |
Field sources (MVP)¶
| Variable | Set by |
|---|---|
Bee, TraceID, TraceTitle, AgentID, TaskID, ColonyRoot, Workspace, Task, Intent, IntentRaw, Insights, ResultFile, Interactive, IsLastWorkTask, Adapter |
internal/runtime.Dispatcher at dispatch time; Interactive is true in internal/sessions for chat |
IsLastWorkTask |
taskledger.IsLastWorkTask at AFK ledger task dispatch (DispatchModeTask) only; always false for CLI bee run, direct signal dispatch, and chat |
TraceTitle |
runs.ResolveTraceTitle from prior trace events and task projections |
Task |
paseka bee run --body (required unless using inline prompt) |
Intent / IntentRaw |
paseka bee run --intent, paseka task create --intent, or intent on task.plan / task.ready payloads |
Insights |
Runtime projection from prior narrative INSIGHT events on the trace, merged with any manual DispatchRequest.Insights |
ResultFile |
Computed from colony root + trace + agent ids |
Variables not available in templates today:
- Bee adapter params (
model,trust, etc.) — configured inbees/*.yaml, not exposed to templates. - Arbitrary bus event fields — only
Task,Intent, andInsightsare surfaced in MVP.
Bus event publishing is instructed through emit partials: emit-howto (safe CLI mechanics for all bees) plus type-scoped partials (emit-insight, emit-signal, emit-verification, emit-task-completed) included only by bees that may publish those types.
4. Template syntax¶
Paseka uses standard Go text/template with no custom functions.
Interpolation¶
Conditionals¶
Loops¶
When Insights is empty, the range produces no lines.
Partials¶
Partials live in .paseka/prompts/_partials/. The file name without .md is the template name:
_partials/emit-howto.md → {{template "emit-howto" .}}
_partials/emit-insight.md → {{template "emit-insight" .}}
_partials/emit-signal.md → {{template "emit-signal" .}}
_partials/emit-verification.md → {{template "emit-verification" .}}
_partials/emit-task-completed.md → {{template "emit-task-completed" .}}
_partials/builder-intent-feature.md → {{template "builder-intent-feature" .}}
Builder Bee uses intent partials for mission-specific guidance while keeping one stable role prompt. The top-level builder.md routes by {{.Intent}} and falls back to builder-intent-general.
Per-bee intent vocabulary¶
Each bee may define an intent vocabulary used for {{.Intent}} normalization and Queen Console intent pickers:
- Explicit —
intents:and optionaldefault_intent:inbees/<role>.yaml(see bee config). - Discovered — when
intentsis omitted, runtime scans_partials/<role>-intent-*.md(e.g.builder-intent-feature.md→feature,drone-intent-grilling.md→grilling).
At dispatch, empty or unknown caller input normalizes to the bee's default intent (general when present, otherwise the first discovered intent). The raw requested value remains in {{.IntentRaw}} when it differs from {{.Intent}}.
Bees without YAML intents and without <role>-intent-* partials have no intent vocabulary; {{.Intent}} stays empty unless the caller passes a recognized value.
Include only the emit partials your bee role may publish:
Partials are loaded before the main template and can use the same variables ({{.TraceID}}, etc.).
5. Override precedence¶
When resolving which template to render, the first non-empty source wins:
| Priority | Source | Example |
|---|---|---|
| 1 (highest) | Inline prompt | paseka bee run builder --prompt "Fix {{.Task}}" |
| 2 | Bee local overlay | .paseka/bees/builder.local.yaml → prompt_template / system_template |
| 3 | Bee config | .paseka/bees/builder.yaml → prompt_template / system_template |
| 4 (lowest) | Colony default | .paseka/colony.yaml → defaults.prompt_template / defaults.system_template |
*.local.yaml files are gitignored — use them for machine- or developer-specific template overrides without committing.
Inline prompts are still parsed as text/template bodies (partials are available).
6. Rendering pipeline¶
bee config + CLI flags
│
▼
Resolve template (precedence §5)
│
▼
Load partials from _partials/
│
▼
Execute text/template with Context (§3)
│
├─► Write system.txt (when system_template configured)
│
▼
Write .paseka/runs/<traceId>/<agentId>/prompt.txt
│
▼
Adapter injects system context (per adapter) and runs external agent
│
▼
Runtime normalizes summary, writes log artifact, may auto-publish `INSIGHT/run.summary`
Bus events are published separately through paseka event emit --stdin (live by default; --defer for end-of-run handoffs) as described in the emit partials. Each bee includes emit-howto plus only the type partials it may publish. Runtime may also synthesize INSIGHT/run.summary after a successful AFK run when the bee policy allows.
7. Examples¶
Builder bee¶
# .paseka/prompts/builder.md
You are Builder Bee. Implement the task in the workspace.
Intent: {{.Intent}}
## Task
{{.Task}}
{{if eq .Intent "bugfix"}}
{{template "builder-intent-bugfix" .}}
{{else}}
{{template "builder-intent-general" .}}
{{end}}
{{template "emit-howto" .}}
{{template "emit-insight" .}}
Known builder intents (discovered from builder-intent-* partials): general (default), feature, bugfix, test-fix, refactor. Drone uses drone-intent-* partials (general, grilling, breakdown) and routes on {{.IntentRaw}} in its template; grilling includes drone-emit-grilling, breakdown includes drone-emit-breakdown. Scout uses scout-intent-* partials (intake default via bee default_intent, survey manual); intake includes scout-emit-intake.
Scout bee with bus-event partial¶
# .paseka/prompts/scout.md
You are Scout Bee. Your job is problem discovery, not implementation.
Colony: {{.ColonyRoot}}
Flight trail: {{.TraceID}}
Intent: {{.Intent}}
## Task
{{.Task}}
## Prior discoveries
{{range .Insights}}- {{.}}
{{end}}
## Mission guidance
{{if eq .Intent "intake"}}
{{template "scout-intent-intake" .}}
{{template "scout-emit-intake" .}}
{{else}}
{{template "scout-intent-survey" .}}
{{end}}
{{template "emit-howto" .}}
{{template "emit-insight" .}}
{{template "emit-signal" .}}
Inline one-shot prompt¶
Renders to: Hotfix only: null pointer in auth
CLI with task and trace¶
{{.Task}} and {{.TraceID}} are filled; other fields come from runtime defaults.
8. Constraints and validation¶
| Rule | Behavior |
|---|---|
| Template path | Must be relative to .paseka/prompts/ |
| Path traversal | .. and absolute paths are rejected |
| Missing template | Dispatch fails with a clear error |
| Missing partial | Dispatch fails at parse time |
| Empty template chain | Error: prompts: no template configured |
9. Shared partials¶
Core partials shipped by paseka init under .paseka/prompts/_partials/:
| Partial | Role |
|---|---|
emit-howto |
Safe CLI publish contract via paseka event emit --stdin (live default, --defer for handoffs; no type enumeration) |
emit-insight |
INSIGHT kinds for narrative and prompt memory (run.summary, review.note, context.note, human.feedback, task.plan) |
emit-signal |
SIGNAL kinds (task.ready) |
scout-emit-intake |
SIGNAL/feature.classified, INSIGHT/task.plan, SIGNAL/task.ready (Scout intake intent only) |
drone-emit-grilling |
SIGNAL/spec.ready + optional context.note (Drone grilling intent only) |
drone-emit-breakdown |
INSIGHT/task.plan, SIGNAL/task.ready, optional context.note (Drone breakdown intent only) |
emit-verification |
Review-gate VERIFICATION kinds (verification.success, verification.failed) |
emit-task-completed |
Commit-gate VERIFICATION/task.completed (receiver only) |
cursor-interactive-kickoff |
Brief greet-and-wait footer for interactive Cursor chat (hivewright-task, drone-task) |
Bees include only the type partials they may publish. For example:
| Bee | Emit partials |
|---|---|
builder |
emit-howto, emit-insight |
scout |
emit-howto, emit-insight, emit-signal; on intake also scout-emit-intake |
drone |
emit-howto; on grilling also drone-emit-grilling; on breakdown also drone-emit-breakdown |
guard |
emit-howto, emit-verification, emit-insight |
main-guard |
emit-howto, emit-verification, emit-insight |
receiver |
emit-howto, emit-task-completed |
hivewright |
emit-howto, emit-insight |
MUTATION is not taught in prompts — runtime auto-publishes code.proposal.isolated or code.proposal.root from baseline-attributed workspace diffs (tracked changes in the adapter cwd; review truth is working-tree git diff, not staged-only). Guard and main-guard prompts instruct disk review via git diff.
See insight kinds for the full INSIGHT taxonomy and prompt-memory rules.
paseka event emit --stdin <<'EOF'
{"traceId":"<traceId>","agentId":"<agentId>","type":"INSIGHT","payload":{"kind":"task.plan","tasks":[{"taskId":"task-1","title":"..."}]}}
EOF
Use {{.TraceID}} and {{.AgentID}} inside partials so examples match the current run. See task ledger.
10. Related docs¶
- architecture overview — colony layout, adapter contract, runs/worktrees
- bee config — bee role YAML (
prompt_templateand other fields) - task ledger — task queue protocol and lifecycle
- glossary — bee language vs technical terms (
TraceID/ Flight Trail,Task/ Nectar) - Agent run file protocol —
request.json,summary.md,events.ndjsonunder.paseka/runs/