Skip to content

Forage Cues (cue layer)

A cue (bee language: Forage Cue) is a project-local YAML shortcut under .paseka/cues/<id>.yaml that publishes one bus ingress action — emit: signal or emit: task — with optional templates for payload fields. One cue definition drives Queen Shell (paseka cue), Queen Console (Run cue), and Telegram (cue: in commands.custom). Cues are shareable colony config (included in Nuc export/import).

Optional standing binds a cue to a long-lived Standing Trail (stable traceId) so recurring procedures reuse the same comb instead of minting a new trail every tick.

Design records: spec 016, spec 028. Vocabulary: glossary (Forage Cue, Standing Trail).

Related: CLI, Telegram gateway, colony layout, task ledger, feature ideation flow, homelab deployment.


1. What cues are (and are not)

Cues do Cues do not
Publish SIGNAL or INSIGHT/SIGNAL task plan (+ optional task.ready) Run bees, start sessions, or accept invites
Seed optional per-cue initial honey on a fresh trace (energy_budget, or standing stipend); standing ticks then replace remaining Top up a live bloom or tick mid-flight (paseka energy add) — that extra is wiped on the next standing stipend
Bind a recurring procedure to a Standing Trail (standing.trace) Ship a scheduler, webhook listener, or report_to callback
Share one definition across CLI, Console, Telegram Replace raw paseka signal / task create for power users
Stay the publish API for timers and GitHub-style hooks (via paseka cue run) Listen for HTTP, run cron, or reply to the webhook caller

Cue success means the bus publish(es) succeeded (and honey seed or standing stipend, when applicable). AFK reactions still need paseka run as today. Timers and inbound HTTP stay outside Paseka — see §10.


2. Layout

.paseka/cues/
├── feature.yaml       # signal → feature.requested (Scout intake)
├── hotfix.yaml        # task → builder bugfix autorun (small energy_budget)
└── daily-triage.yaml  # optional standing procedure (stable trace + stipend)

Cue id = filename without extension. paseka init scaffolds feature and hotfix when missing.


3. Authoring

Signal cue (feature)

# .paseka/cues/feature.yaml
description: Intake an idea or bug for Scout classification
emit: signal
type: SIGNAL
kind: feature.requested
title: "{{.Title}}"
body: "{{.Body}}"

Publishes one SIGNAL on a new trace (or --trace / API traceId when attaching). Omitted energy_budget → colony default applies on first seed (see §5).

Task cue (hotfix)

# .paseka/cues/hotfix.yaml
description: Urgent fix via builder (small honey reserve)
emit: task
bee: builder
intent: bugfix
review: none
autorun: true
energy_budget: 3
title: "{{.Title}}"
body: "{{.Body}}"

Reuses task create semantics: INSIGHT/task.plan, then SIGNAL/task.ready when autorun: true.

Standing cue (recurring procedure)

# .paseka/cues/daily-triage.yaml
description: Daily triage
emit: signal
type: SIGNAL
kind: triage.tick
standing:
  trace: trail-daily-triage
  stipend: 4
title: "{{.Title}}"
body: "{{.Body}}"

paseka cue run daily-triage "tick …" without --trace publishes on trail-daily-triage. An explicit --trace that equals that id is allowed; any other id fails closed. Non-standing cues still mint a new trail when --trace is omitted.

Standing is a cue binding, not a ledger flag. Recommended ids look like trail-daily-triage (hyphens, no dots). Two standing cues may not share one standing.trace. energy_budget is forbidden on a standing cue — stipend is the only honey number. A bare standing: key (null / empty) is rejected, not treated as a bloom cue.

Standing emit: task cues require review: none (or omit review) and the named bee must have worktree: false. Load/import errors name the cue, bee, and field.

First successful run seeds honey from standing.stipend and, if the trail has no INSIGHT/trace.title yet, publishes one from cue description (trimmed, 120-character cap) or the cue id when description is empty. Later ticks do not overwrite a human or bee title. Each later run publishes SIGNAL / energy.stipend before ingress, which sets energyRemaining to the stipend (does not add, does not change energyBudget / energyAdded, does not unblock leftover honey-blocked tasks). A killed standing trail refuses cue run (no stipend, no ingress); the error names system.kill. A second tick is refused while any ledger task is planned, ready, running, or waiting_review, or a live AFK adapter is still running on that trail (interactive bee chat does not count).

paseka doctor warns (does not fail the cue) when a standing emit: signal kind has only worktree: true direct subscribers, when a standing tick bee publishes isolated code.proposal, or when an isolated proposal already appears on a standing trail. Config profiles do not overlay cues or stipend (027 out of overlay).

Checkpoints and bloom spawn

Standing ticks observe and record. Procedure memory is the trail comb ({{.ArtifactsDir}} = .paseka/runs/<standing.trace>/artifacts/), not {{.Insights}}. Recommended files:

File artifactKind (014 basename-stem) Role
checkpoint.json checkpoint Source of truth (skip lists, keys, SHAs)
journal/YYYY-MM-DD.md date basename (e.g. 2026-09-04) Optional human journal; 014 kind is basename-stem, not the journal/ folder

The comb path is stable for the standing traceId, so the next tick sees yesterday’s files. Runtime still scan-flushes artifact.written only on content change (014). Prompt partial standing-checkpoint (included from emit-howto) tells bees to read the checkpoint first, write JSON via temp-file replace, and spawn a bloom (paseka cue run <feature-or-hotfix> "…" with no standing binding, or signal/event emit with a new traceId) instead of task.plan a builder on the procedure. Optional watch-intent-tick is for Watch/Medic bees. Hivewright edits of cues/prompts belong on a bloom hivewright trail with code.proposal.root.

paseka purge --runs deletes standing checkpoints with the rest of .paseka/runs/. Facts the colony must keep belong in git (docs/, tracker), not the comb. Export --include artifacts still dumps the standing comb. Queen Console Artifacts can preview checkpoint.json like any comb JSON.

Ad-hoc bee run / bee chat on the standing id shares the comb and does not apply stipend.

Schema (MVP)

Field Required Notes
description no Shown in cue list, Console picker, Telegram help fallback. First standing seed also uses it as INSIGHT/trace.title (cue id if empty)
emit yes signal or task
energy_budget no Positive int — initial honey override on an unseeded bloom trail (§5). Forbidden when standing is set
standing.trace with standing Stable Flight Trail id used when the caller omits --trace / traceId. No spaces, path separators, ., *, or > (JetStream KV keys)
standing.stipend with standing Positive int — first-tick seed and per-tick remaining ration (§5). Required whenever standing is present
signal
type yes Must be SIGNAL
kind yes payload.kind (e.g. feature.requested)
static no Extra string fields merged into payload
title, body no* text/template strings (*required when templates reference them)
payload_template no Escape hatch: rendered string → JSON object
task
bee, intent, review, autorun per task create Same semantics as paseka task create
title, body no* Templates for task plan fields

Template engine: Go text/template (same family as prompt templates). Built-in context:

Key Meaning
Text Operator text (positional CLI arg, Console modal, Telegram command body)
Title First line of Text
Body Full Text
Source Calling channel: cli, console, or telegram (scripted cue run is cli today)
TraceID Resolved flight trail

Extra vars: --set key=val (CLI) or vars map (Console API). Missing template keys → error. Unused --set keys are ignored. Operator Text / --set wins over cue static defaults.


4. Queen Shell

paseka cue list [-C path]
paseka cue run <id> <text> [--trace id] [--set key=val ...] [-C path]
Command Behavior
cue list Stable sort by id; prints id, optional standing trail id, optional description
cue run Publishes immediately (no confirm). Prints trace id; task id when emit: task. Standing cues resolve --trace as above

Examples:

paseka cue run feature "OAuth callback returns 500 on refresh"
paseka cue run hotfix "Fix nil deref in token refresh"
paseka cue run feature "Follow-up on same trail" --trace trace-abc123
paseka cue run daily-triage "tick $(date -I)"

Requires NATS (same as paseka signal / task create). See CLI § paseka cue. systemd/cron and GitHub should invoke this command on the hive host — not a Paseka listener (§10).


5. Honey: energy_budget vs colony default vs energy add

Bloom seed and top-up, plus standing seed and per-tick replace:

Mechanism When Effect
defaults.energy_budget in colony.yaml First seed on a trace (task create, reactor ensure-seed, cue without override) Sets initial energyBudget / energyRemaining (default 12)
Cue energy_budget Fresh bloom trail only (energyBudget == 0 on snapshot) Seeds a smaller or custom initial reserve via ledger SeedEnergy — can be less than colony default
Standing first-tick seed Fresh standing trail (energyBudget == 0) Seeds energyBudget / energyRemaining from standing.stipend (same SeedEnergy primitive)
Standing later tick Standing trail already seeded, not killed, not busy Publishes SIGNAL / energy.stipend before ingress; sets energyRemaining to stipend. Does not change budget or energyAdded. Does not unblock honey-blocked tasks from a previous tick
paseka energy add Any time (live bus) Increments energyRemaining; after seed also increments energyAdded. Does not change energyBudget. Unblocks honey-blocked tasks on a live tick; the next standing stipend wipes leftover remaining back to stipend

Rules:

  • Omit energy_budget on a non-standing cue → unchanged colony-default seeding.
  • Cue with energy_budget on a new bloom trail → seed before publish (signal and task paths).
  • Standing cue on a new trail → seed from stipend before publish; also publish trace.title from description (or cue id) when none exists.
  • Standing cue on a seeded trail → replace remaining with stipend, then publish ingress (does not overwrite trace.title).
  • cue run --trace (or Console/Telegram traceId) on a bloom trail that already has honey → cue energy_budget seed is ignored (no shrink, no re-seed).
  • Killed standing trail → cue run fails closed (names system.kill); no stipend event, no ingress.
  • Standing trail with an open tick (planned / ready / running / waiting_review) or a live AFK run on that traceId → cue run fails closed (error says the trail is busy); no stipend, no ingress. blocked / completed / failed / cancelled and interactive sessions do not block.
  • Cues never emit energy.add — use CLI, Console, or Telegram /energy for a live-tick extra token.

Full ledger model: task ledger § Honey reserve.


6. Queen Console

Hive Dashboard and header expose Run cue:

  1. Picker lists cue id + optional description (no emit-type badge). Standing cues also show Standing: <traceId>. GET /api/cues returns standingTrace when the cue declares standing.
  2. Enter text (and optional trace id in the API; omit it on a standing cue to use standing.trace).
  3. On success: toast with clickable traceId link to the trace view.

Trail lists (Dashboard and Traces) show a standing badge on ids declared by a loaded standing cue, and trail detail marks the flag plus honey as remaining / stipend. The badge follows colony YAML, not a ledger flag: delete the cue and the trail looks like an ordinary leftover trail. GET /api/traces, /api/traces/:id, and /api/dashboard carry standing: true for those ids.

API (NATS required):

Method Path Body
GET /api/cues —
POST /api/cues/:id/run {"text":"…","traceId":"…","vars":{}}

traceId and vars are optional. Omitting traceId on a standing cue uses standing.trace (same as CLI). agentId / source are console. This API is for Queen Console on a trusted network (homelab); it is not a public GitHub/webhook endpoint.


7. Telegram gateway

In ~/.config/paseka/<slug>/telegram.yaml, commands.custom.<name> may use cue: <id> instead of inline emit / type / kind:

commands:
  custom:
    feature:
      description: "Intake idea/bug via Scout"
      cue: feature
  • Loads .paseka/cues/feature.yaml from the colony repo.
  • Preview + Confirm stay in the gate (same as /task and inline emit: signal). Standing cues show the standing trail id and confirm publishing on that trail (not “a new trace”).
  • description in gate config wins; falls back to cue description.
  • Inline emit: signal custom commands still work — migration is optional.

Reserved command names unchanged: start, status, help, invites, traces, energy, task.

See Telegram gateway § Custom commands.


8. Nuc packs

Cues export and import with bees and prompts:

paseka nuc export -o pack.nuc.yaml              # includes all cues when present
paseka nuc export --cues feature,hotfix -o …    # filter cue ids
paseka nuc import ./pack.nuc.yaml

Nuc spec.cues maps id → raw YAML body. Import validates cue files. Details: Nuc packs.


9. Ideation entry

For the reference ideation flow, paseka cue run feature "…" is the everyday replacement for hand-written SIGNAL/feature.requested. Scout intake still reacts via subscribes when paseka run is active.

paseka cue run feature "Live bees indicator in Console header"
# equivalent to publishing feature.requested on a new traceId

See feature ideation flow § Entry paths and § Soft bootstrap.


10. External timers and webhooks

Colony YAML says what to publish (.paseka/cues/<id>.yaml). The apiary says when and from where. Paseka does not ship an HTTP webhook receiver, a cron dispatcher, or delivery back to the caller (report_to). Telegram mode: webhook is bot transport (Telegram gateway), not generic ingress.

Layer Owns Lives in
Cue definition Mnemonic + payload templates .paseka/cues/ (git, Nuc)
Schedule / hook systemd timer, GitHub Actions, a small signed-webhook wrapper Machine / CI — not the colony repo
Hive liveness JetStream + reactor paseka run; probe with paseka status --check

Cue success ≠ bees running. paseka cue run publishes even if the reactor is down. A timer that must start work should probe first (paseka status --check), then run the cue. See CLI (paseka status --check, paseka cue).

Do not point GitHub (or any internet webhook) at POST /api/cues/:id/run. Use SSH or a self-hosted runner on the hive host and call Queen Shell. Map provider JSON to cue Text / --set in the wrapper — cue files stay GitHub-agnostic (no stdin / --file on cue run).

Idempotency is the wrapper’s job. On a non-standing cue, omitting --trace always starts a new trail; a retried GitHub delivery or a double timer tick otherwise burns a second honey reserve. Remember delivery_id or job@slot and skip the second cue run. Recurring procedures should declare standing so omitted --trace reuses the procedure identity; Paseka also refuses a second tick while the trail is busy. The wrapper should still skip a double fire when it can.

Examples (apiary-local; adjust -C / paths):

# systemd / cron: probe hive, then tick a standing procedure
paseka status --check -C /path/to/colony && \
  paseka cue run daily-triage "tick $(date -I)" -C /path/to/colony

# bloom hotfix from CI on a self-hosted runner next to the hive (new trail each run)
paseka cue run hotfix "$ISSUE_TITLE" -C "$COLONY_ROOT"

Scheduled cues still need an active paseka run (and NATS) for AFK bees. Put schedules in machine config, not in committed .paseka/.