Skip to content

Validate an artifact before the LLM sees it

Goal: Catch malformed input before the LLM is called, and surface findings to the LLM so it can react (ask the user, reject, fall back).

When to use

  • The input artifact has a structure that's expensive for the LLM to vet (long lists, nested objects, optional fields with cross-field constraints).
  • You want a deterministic gate, not "the LLM will probably notice."

Pattern

Add a validate step to the phase's preprocessor. Findings land at into; the LLM reads them like any other input field.

---
type: phase
name: triage
input: ticket_batch
preprocessor:
  - validate:
      schema:
        type: object
        required: [tickets]
        properties:
          tickets:
            type: array
            items:
              type: object
              required: [id, title]
              properties:
                id: { type: string }
                title: { type: string, minLength: 1 }
      target: input
      into: validation_findings
---

Triage each ticket into `bug`, `feature`, or `chore`. If
`validation_findings.errors` is non-empty, ask the user to fix the
input before triaging.

What validation_findings looks like

{
  "errors":   [{"path": "tickets[3].title", "message": "must NOT be shorter than 1 chars"}],
  "warnings": [],
  "valid":    false
}

The LLM reads it under whatever key you set in into. Phase instructions reference findings by name only — they do not need to know the schema (P8).

Where validation already happens for free

You don't need a validate step for either of these — the OS does it:

  • Transition validation. Every artifact is validated against the next phase's input schema before the transition.
  • Final output validation. The terminating artifact is validated against the skill's final_output declaration.

Use validate only when you want validation inside the phase, before the LLM call.

See also