Files
roboco/docs/rag/architecture/agent-doctrine.md
T
cebbd73e07 Ponytail build-laziness doctrine (bundled with Fable, 0.19.0) (#313)
* feat(agents): vendor trimmed ponytail doctrine (full + ethos)

* feat(agents): compose ponytail doctrine layer, bundled with fable

* docs: document ponytail doctrine bundled with fable-mode

* style: add trailing newline to ponytail doctrine files test

* docs: changelog + map/rag for ponytail doctrine (0.19.0)

user-facing docs skipped: Fable precedent absent from README/deployment/usage; ponytail is default-off internal.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-05 20:48:11 +02:00

5.3 KiB

Agent Doctrine Layers

How compose_prompt (roboco/agents/factories/_base.py) assembles an agent's system prompt at spawn, and where the optional doctrine layers sit. Doctrine is prompt-only — no hooks, no grok-path changes — and gated by a single flag.

Layer order

compose_prompt(role, team, agent_slug, base_path=None, ambient=None) concatenates these layers with --- separators, skipping any that resolve to empty/None:

  1. _tool_load_directive_layer(role) — top-of-prompt "your tools are ready" block.
  2. _lifecycle_layer(prompts_path, role) — autogenerated verb-surface fragment (_generated/lifecycle-<role>.md).
  3. base.md — universal base rules (identity separation, envelope shapes, ground rules).
  4. fable_doctrine_layer(prompts_path) — vendored Fable behavioral doctrine (0.18.0).
  5. ponytail_doctrine_layer(prompts_path, role) — vendored Ponytail build-laziness doctrine (0.19.0), role-scoped, bundled with Fable.
  6. _role_layer(prompts_path, role) — role prompt (roles/<role>.md).
  7. _autogen_verbs_layer(prompts_path, role) — per-role verb-signature table.
  8. _team_layer(prompts_path, team) — team prompt (teams/<team>.md).
  9. Identity file (identities/<slug>.md).
  10. ambient — optional architectural-conventions ambient block (conventions_ambient_layer).

The order is load-bearing: lifecycle precedes base so the agent reads its allowed verb surface before any other instruction. Reordering changes model attention priority.

Fable doctrine (0.18.0)

fable_doctrine_layer(prompts_path) returns the vendored agents/prompts/doctrine/fable.md text, or None when settings.fable_mode_enabled is off / the file is missing. Source: github.com/rennf93/opus-fable-playbook (MIT), YAML frontmatter stripped. Covers communication, turn-discipline, autonomy-calibration, honesty, code-discipline, delegation, precedence. Slotted right after base.md. When the flag is on, the Fable hooks (docker/scripts/fable-*.sh) are also installed at spawn on the Claude runtime (and a non-denying honesty-nudge hook on grok) — those hooks are out of scope for this chunk; this file is about the composed prompt only.

Ponytail doctrine (0.19.0)

ponytail_doctrine_layer(prompts_path, role) returns the vendored Ponytail build-laziness doctrine, gated on the same fable_mode_enabled flag (no separate flag — ponytail is Fable's complementary build-doctrine). Slotted into compose_prompt immediately after fable_doctrine_layer. Role-scoped:

  • Developers (AgentRole.DEVELOPER) → agents/prompts/doctrine/ponytail.md: the full ladder (YAGNI → reuse-in-this-codebase → stdlib → native-platform → installed-dep → one-line → minimal), the rules, the ponytail: comment convention, an Intensity table, and a 5-point RoboCo preamble that makes the ladder yield to the Architectural Conventions Standard (placement), the 80% coverage gate + QA review + self-verification, the per-team design bar, task hygiene, and reviewer feedback. The layer appends a one-line **Operative intensity: {settings.ponytail_intensity}.** directive that the Intensity table resolves into concrete behavior.
  • Every other roleagents/prompts/doctrine/ponytail-ethos.md: the ethos-only cut — the code-mechanics rungs (the ladder) and the Intensity table are removed so they can't leak into prose artifacts (task plans, review notes, docs). The 6th preamble point guards free-text field obligations (ac_verdicts, findings, dev_notes, qa_notes). No intensity directive (ethos runs a fixed restrained stance regardless of ponytail_intensity).

Source: ponytail plugin (MIT, Copyright (c) 2026 DietrichGebert), vendored trimmed, YAML frontmatter stripped. Both doctrine files are static markdown with no DB/project dependency — the layer resolves synchronously inside compose_prompt, like fable_doctrine_layer.

None when the flag is off or the file is missing, so a flag-off spawn is byte-for-byte unchanged.

Intensity knob

ROBOCO_PONYTAIL_INTENSITY (env) / settings.ponytail_intensity (roboco/config.py, Literal["lite","full","ultra"], default full). A string value, not a feature flag — no FEATURE_FLAGS entry, no panel toggle. pydantic validates the Literal at Settings instantiation, so an invalid env value raises at startup.

Level Developer behavior
lite Build what's asked; name the lazier alternative in a ponytail: note, don't impose it.
full The ladder enforced. Stdlib and native first, shortest working diff, shortest explanation. Default.
ultra YAGNI extremist: deletion before addition, challenge the requirement before the rung. Still bounded by the preamble (reviewer feedback and explicit requests win).

Non-developers get no dial — ultra is wrong for prose artifacts, so the ethos runs a fixed restrained stance regardless.

Files

File Purpose
agents/prompts/doctrine/fable.md Fable behavioral doctrine (0.18.0).
agents/prompts/doctrine/ponytail.md Ponytail full doctrine — developers (0.19.0).
agents/prompts/doctrine/ponytail-ethos.md Ponytail ethos-only — non-developers (0.19.0).
roboco/agents/factories/_base.py compose_prompt, fable_doctrine_layer, ponytail_doctrine_layer.
roboco/config.py fable_mode_enabled (gates both), ponytail_intensity (string value).