Skip to content

prompt

prompt

PromptRenderer — full prompt rendering for baton musicians.

Bridges the PromptBuilder pipeline with the baton's Sheet-based execution model. Replaces the bare-bones _build_prompt() in musician.py with the full 9-layer prompt assembly:

1. Preamble (positional identity)
2. Template rendering (Jinja2 with all variables)
3. Skills/tools injection (prelude/cadenza with category=skill/tool)
4. Context injection (prelude/cadenza with category=context)
5. Spec fragments (from specification corpus)
6. Failure history (from previous sheets)
7. Learned patterns (from learning store)
8. Validation requirements (as agent-readable checklist)
9. Completion suffix (for completion mode retries)

The renderer is intentionally stateless — create one per job, call render() per sheet. No runner dependency, no mixin inheritance.

This is the F-104 fix. Without it, the baton produces raw templates instead of rendered prompts.

See: docs/plans/2026-03-26-baton-design.md — Prompt Assembly

Classes

RenderedPrompt dataclass

RenderedPrompt(prompt, preamble)

Output of the prompt rendering pipeline.

Contains both the rendered prompt (for backend execution) and the preamble (set on the backend before execution). Separating them allows the musician to configure the backend correctly.

Attributes
prompt instance-attribute
prompt

Fully rendered prompt with all injections and context layers.

preamble instance-attribute
preamble

Dynamic preamble with positional identity and retry status.

PromptRenderer

PromptRenderer(prompt_config, total_sheets, total_stages, parallel_enabled)

Renders full prompts for baton musicians.

Bridges the PromptBuilder pipeline with the baton's Sheet-based execution model. Handles template rendering, injection resolution, preamble assembly, and validation requirements — everything the old runner's context mixin did, but without the runner dependency.

Create one per job (or share across jobs with the same config). Call render() per sheet dispatch.

Parameters:

Name Type Description Default
prompt_config PromptConfig

The job's PromptConfig (template, variables, etc.).

required
total_sheets int

Total sheets in the job (for preamble).

required
total_stages int

Total stages before fan-out expansion (for template aliases).

required
parallel_enabled bool

Whether parallel execution is enabled (for preamble).

required
Source code in src/marianne/daemon/baton/prompt.py
def __init__(
    self,
    prompt_config: PromptConfig,
    total_sheets: int,
    total_stages: int,
    parallel_enabled: bool,
) -> None:
    self._prompt_config = prompt_config
    self._total_sheets = total_sheets
    self._total_stages = total_stages
    self._parallel_enabled = parallel_enabled
Functions
render
render(sheet, attempt_context, *, patterns=None, failure_history=None, spec_fragments=None)

Render a full prompt for a sheet execution.

Performs the complete 9-layer prompt assembly: template rendering -> injection resolution -> optional layers -> validation requirements -> completion suffix.

Parameters:

Name Type Description Default
sheet Sheet

The Sheet entity to render for.

required
attempt_context AttemptContext

Context from the baton (attempt number, mode).

required
patterns list[str] | None

Optional learned pattern descriptions to inject.

None
failure_history list[HistoricalFailure] | None

Optional historical failures from previous sheets.

None
spec_fragments list[SpecFragment] | None

Optional spec corpus fragments to inject.

None

Returns:

Type Description
RenderedPrompt

RenderedPrompt with fully rendered prompt and preamble.

Source code in src/marianne/daemon/baton/prompt.py
def render(
    self,
    sheet: Sheet,
    attempt_context: AttemptContext,
    *,
    patterns: list[str] | None = None,
    failure_history: list[HistoricalFailure] | None = None,
    spec_fragments: list[SpecFragment] | None = None,
) -> RenderedPrompt:
    """Render a full prompt for a sheet execution.

    Performs the complete 9-layer prompt assembly:
    template rendering -> injection resolution -> optional layers ->
    validation requirements -> completion suffix.

    Args:
        sheet: The Sheet entity to render for.
        attempt_context: Context from the baton (attempt number, mode).
        patterns: Optional learned pattern descriptions to inject.
        failure_history: Optional historical failures from previous sheets.
        spec_fragments: Optional spec corpus fragments to inject.

    Returns:
        RenderedPrompt with fully rendered prompt and preamble.
    """
    # Layer 1: Build SheetContext from Sheet entity (F-210: includes cross-sheet)
    context = self._build_context(sheet, attempt_context)

    # Layer 2-3: Resolve prelude/cadenza injections into the context
    self._resolve_injections(context, sheet)

    # Layer 4-8: Build prompt through PromptBuilder
    prompt = self._build_prompt(
        sheet, context, patterns, failure_history, spec_fragments
    )

    # Layer 9: Completion mode suffix
    if attempt_context.completion_prompt_suffix:
        prompt = f"{prompt}\n\n{attempt_context.completion_prompt_suffix}"

    # Preamble: positional identity + retry status
    retry_count = max(0, attempt_context.attempt_number - 1)
    preamble = build_preamble(
        sheet_num=sheet.num,
        total_sheets=self._total_sheets,
        workspace=sheet.workspace,
        retry_count=retry_count,
        is_parallel=self._parallel_enabled,
    )

    return RenderedPrompt(prompt=prompt, preamble=preamble)

Functions