Skip to content

Add beads-prime builtin processor: inject 'bd prime' memories at conversation start #56

Description

@inercia

Goal

Add a builtin processor that injects beads memories/workflow context (via bd prime)
at the beginning of a conversation, so agents start with persistent beads memories
loaded automatically.

Reference: https://gastownhall.github.io/beads/cli-reference/prime

bd prime --memories-only outputs only persistent memories (compact) — the best match
for "beads memories at the start of a conversation". .beads/PRIME.md can override the
content. Output is raw markdown (NOT JSON).

Key engine constraints discovered

  1. Command-mode stdout MUST be valid JSON (executor.parseOutput does json.Unmarshal
    into ProcessorOutput{message,text,...}). Raw bd prime markdown fails to parse →
    processor skipped under on_error:skip. So command: bd, args:[prime] does NOT work
    as-is.
  2. TWO divergent command-mode paths:
    • ApplyProcessors (standalone): honors output: prepend/append/transform.
    • Manager.applyWithRerun (used whenever any prompt-mode processor is loaded — almost
      always, since builtins like memorize-preferences are prompt-mode — AND on every
      rerun): IGNORES output: type, always does result.Message = output.Message. With
      output:transform this REPLACES the user message with prime text (data loss). This is
      effectively a bug.
  3. Companion scripts don't work cleanly for builtins: embed glob is
    //go:embed processors/builtin/*.yaml (YAML only) and builtins deploy at 0644.
  4. No builtin currently uses command-mode → safe to enhance command-mode output handling.
  5. Working dir defaults to sessionbd prime runs where .beads/ lives. Good.

Recommended approach (Option B): native raw-text command output + pure-YAML builtin

Dependency-free (no jq, no companion script), works as a builtin, improves command-mode
generally.

Go changes in internal/processors:

  1. types.go: add OutputFormat field (outputFormat: raw|json, default json) +
    GetOutputFormat().
  2. executor.go: when outputFormat:raw, skip json.Unmarshal; set BOTH output.Message and
    output.Text to trimmed stdout (works in either code path).
  3. apply.go applyWithRerun command branch (~L701-730): honor output: type
    (transform/prepend/append/discard) mirroring ApplyProcessors, and chain
    input.Message = result.Message. REQUIRED bug fix — otherwise output:prepend silently
    degrades to transform and drops the user message.
  4. loader.go: validate outputFormat in {raw,json}; only meaningful for command-mode.

Builtin config/processors/builtin/beads-prime.yaml:

name: beads-prime
enabledWhen: 'commandExists("bd") && dirExists(".beads")'
when: { on: userPrompt, match: first, rerun: { afterTime: 30m, afterSentMsgs: 20, afterTokens: 80000 } }
command: bd
args: [prime, --memories-only]
input: none
output: prepend
outputFormat: raw
priority: 92
timeout: 10s

Docs/tests: update docs/config/processors.md (new outputFormat field + command-mode
example) and .augment/rules/05-msghooks.md (builtin table + field). Add executor
raw-output test, apply rerun-path prepend test, loader validation test, and the
builtin-validity test.

Alternative (Option A): workspace companion script (no Go changes)

Ship as a workspace processor (.mitto/processors/, where ./script.sh resolves on disk),
output: transform, script reads stdin .message, runs bd prime, emits
{"message": "<prime>\n\n---\n\n<original>"}. Requires jq, only works per-workspace
(not a builtin), leans on the transform path. More fragile; not recommended for a shipped
feature.

Acceptance criteria

  • A builtin beads-prime processor injects bd prime --memories-only output at the start
    of a conversation when bd exists AND .beads/ exists.
  • The user's original message is preserved (prepended, not replaced) in BOTH the
    standalone and rerun code paths.
  • No new runtime dependency (no jq) for the builtin.
  • Tests cover raw-output execution, rerun-path prepend, and loader validation.
  • Docs and .augment/rules updated.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions