Skip to content

Use strict template for prompts #77

@VincentShipsIt

Description

@VincentShipsIt

name: strict-prompt-template-engine
description: Render WORKFLOW.md prompt bodies with a Liquid-compatible engine configured to fail on unknown variables and filters, preventing silently corrupted agent prompts.
status: backlog
estimated_complexity: low
blast_radius: contained

Use strict template for prompts

Executive Summary

WORKFLOW.md (#65) introduces user-authored prompt templates. If the rendering engine silently turns {{ issue.titel }} into an empty string, the agent receives a malformed prompt and burns turns on garbage input. Symphony (SPEC §5.4) requires a Liquid-compatible engine configured strictly: unknown variables and unknown filters MUST fail rendering. This issue lands the same contract for ShipCode so configuration typos surface immediately, not three minutes into a wasted agent run.

Problem Statement

Today's pipeline prompt is a hardcoded template literal in packages/pipeline/src/pipeline.ts:148. Once #65 ships and that string moves to a user-edited WORKFLOW.md, the rendering layer becomes the place where typos die — silently or loudly. Default-permissive rendering produces silent failures: agents see an empty {{ issue.titel }} and proceed. We want loud failures: render error → fail the attempt with a clear message.

Goals

  • Pick a Liquid-compatible renderer with strict modes available (liquidjs is the obvious candidate).
  • Configure both strictVariables: true and strictFilters: true.
  • Surface render failures as a typed error in pipeline state so the UI can show the offending template line.
  • Provide a small set of input objects (issue, attempt, phase) consumed by templates.

Non-Goals

  • Not designing the full WORKFLOW.md schema (that's Add WORKFLOW.md target-repo policy #65).
  • Not adding custom filters in this issue beyond what the engine ships with.
  • Not building a template editor UI.

User Stories with Acceptance Criteria

Story 1: Typo fails immediately

  • As a user who typed {{ issue.titel }}, I see a clear error before any agent runs.
  • Acceptance: pipeline state transitions to template_render_error with the variable name; no agent process is spawned for that attempt.

Story 2: Valid template renders unchanged

  • As a user with a correct template, I see the rendered prompt sent to the agent.
  • Acceptance: rendered output equals the expected interpolation; no warnings logged.

Story 3: Unknown filter fails

  • As a user who wrote {{ issue.title | uppercas }}, I see a render error naming the filter.
  • Acceptance: error message includes uppercas; attempt does not proceed.

Functional Requirements

  • Renderer module at packages/pipeline/src/template-renderer.ts exporting renderTemplate(source: string, ctx: TemplateContext): string and a typed TemplateRenderError.
  • Inputs available to templates: issue (number, title, body, labels, state), attempt (number, prior_failure_reason?), phase (plan|review|execute|verify).
  • Render failures throw TemplateRenderError carrying the original engine error message and source line if available.
  • Pipeline catches the error, records template_render_error on the attempt, and surfaces it via the standard pipeline-event emitter.
  • No silent fallbacks — never substitute empty string for a missing variable.

Non-Functional Requirements

  • Render of a 10KB template completes in under 50ms.
  • Engine choice must be MIT/Apache-compatible.
  • No template eval may execute filesystem or network operations.

Success Criteria

  • A unit test rendering {{ issue.titel }} against a valid issue object throws TemplateRenderError.
  • A unit test rendering {{ issue.title | uppercas }} throws with the filter name in the message.
  • A pipeline-level test confirms the failed render does not spawn an agent process.
  • A unit test rendering a known-good template returns the expected string.

Out of Scope

  • WORKFLOW.md file format and discovery (Add WORKFLOW.md target-repo policy #65).
  • Custom filter library.
  • Template editor / live preview.
  • Multi-language template engines (Jinja, Handlebars, etc.).

Dependencies

Verification Plan

  • Unit tests for: missing variable, missing filter, valid render, deep object access (issue.labels[0].name).
  • Pipeline integration test: stub WORKFLOW.md with a typo, run a phase, assert state machine transitions to error without spawning agents.
  • Performance check: render a 10KB template 100 times, assert mean under 50ms.

Risks & Open Questions

  • Risk: liquidjs may have surprising quirks around whitespace control; document the chosen settings.
  • Risk: Errors from the renderer may be cryptic; wrap with a friendlier message naming the offending token.
  • Open Q: Do we need a dry-run CLI command that just renders the template against a sample issue, for users to debug locally?
  • Open Q: Should we ship a default WORKFLOW.md so users have a working starting point?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions