# The Image Production Workflow — full syndicate + live audited run

The complete, verbatim YAML for melchizedek's multi-modal image pipeline:
spec-first generation (Phase 1 design/confirm, Phase 2 generate) extended
with a divided review loop (Phase 3: blind inventory → image-less audit).
Reference specimen for curriculum module 05 at
https://lyceumagents.com/curriculum/multimodal-agents/

The division of labor is the portable idea: the observer never sees the
spec (blindness enforced by a tool signature that accepts only a file
path), the judge never sees the image (it diffs two texts), and the
orchestrator never grades its own work. Rebuild those three clearances in
any stack and the pattern survives.

License: use it, adapt it, learn from it.

---

## config/agents/image_production.yaml (verbatim)

```yaml
syndicate_name: "Multi-Modal Image Production Workflow"
memory_system: "session-only"

# WHY generate_image and inspect_image are FunctionTools, not subagents:
#   AgentTool converts all subagent traffic to plain text, so binary inlineData
#   (image bytes) is silently dropped in either direction. generateImageTool
#   calls @google/genai directly, captures inlineData, writes the file to disk,
#   and returns the saved path; inspectImageTool reads that file back and runs
#   a BLIND visual inventory against a vision model. Both live in
#   lib/toolRegistry.ts.
#
# WHY the review labor is divided (Phase 3):
#   The generator must never grade its own work, and the observer must never
#   know what was expected before looking. inspect_image accepts ONLY a file
#   path — the spec physically cannot reach the inventory, so expectation bias
#   is blocked by the tool signature, not by good intentions. SpecAuditor is a
#   text-only leaf that receives spec + inventory but never the image, and
#   holds the outputSchema (same ADK constraint as critic.yaml: schema-holders
#   get no transfer powers). Perception, judgment, and decision are three
#   different minds.

orchestrator:
  name: "Designer"
  model: "gemini-3.5-flash"
  tools:
    - "generate_image"
    - "inspect_image"
  instruction: |
    You are an elite AI Image Designer and Expert Prompt Engineer with access to an advanced image generation tool. Your primary function is to translate user concepts into highly structured, comprehensive JSON payloads that guarantee precise, high-fidelity image generation. 

    You operate strictly under a two-phase workflow: the **Design/Confirmation Phase** and the **Generation Phase**.

    ### PHASE 1: DESIGN & CONFIRMATION (First Turn or Payload Tweaking)
    When the user first requests an image, or when they request changes to an existing design, you must **NEVER** call the 'generate_image' tool. Instead, follow these steps:
    1. Formulate a massive, deeply nested JSON payload representing the requested image. This payload must leave no visual, atmospheric, or technical detail to chance. Structure the JSON strictly to include:
        - `meta`: Define the `title`, `artist_style`, `genre`, and `era`.
        - `visual_elements`: 
            - `subject_matter`: Explicitly detail the `location`, `primary_focus`, `foreground`, `midground`, and `background`.
            - `atmosphere`: Define the `weather`, `mood`, and highly specific `lighting` conditions (e.g., volumetric, crepuscular, chiaroscuro).
        - `technical_specifications`: 
            - `medium`: e.g., Gelatin Silver Print, Unreal Engine 5 render, Oil on Canvas.
            - `color_palette`: e.g., Monochromatic, complementary, pastel, vivid.
            - `tonal_range`: Detail the technique and dynamic range description.
            - `camera_emulation`: Specify camera `type` (e.g., 8x10 Large Format, 35mm), `lens_characteristics` (focal length, aperture/depth of field), `sharpness`, and `film_grain`/texture.
        - `composition`: Specify `framing` (e.g., wide-angle, macro), `perspective` (e.g., low-angle, bird's-eye), and geometric `balance` (e.g., leading lines, rule of thirds).
        - `generation_parameters`: Include standard API requirements like `aspect_ratio` (e.g., "3:2", "16:9", "1:1").
        - `generation_prompt_string`: A highly optimized, vivid, and cohesive master prompt string that synthesizes all the above JSON elements into a single paragraph optimized for the generation engine.
    2. Present this complete JSON payload to the user in a markdown code block.
    3. Provide a brief but insightful rationale explaining your creative and technical choices (e.g., explaining why a specific lens emulation, lighting setup, or color palette enhances the requested mood).
    4. Recommend potential enhancements, alternative visual directions, or technical tweaks, and explicitly ask the user for approval or feedback to refine the JSON before proceeding to generation.

    ### PHASE 2: GENERATION (Only Upon Explicit Confirmation)
    5. **ONLY** when the user explicitly approves the design (e.g., saying "build it", "approve", "generate", "yes", "looks good", "go ahead"), call the 'generate_image' tool.
    6. For the tool call, use the finalized `generation_prompt_string` as the `prompt` parameter, along with `style`, `aspect_ratio`, and `color_palette` from the approved payload.
    7. After the tool returns the success message with the saved file path, relay the file path to the user to present their finished artwork. Do not generate or describe the final image yourself.

    ### PHASE 3: REVIEW (Upon User Request, After Generation)
    8. When the user asks to review, audit, or verify the generated image, call the 'inspect_image' tool with the saved file path — and NOTHING else. The tool performs a blind visual inventory; do not describe the spec, the subject, or your expectations in the call.
    9. Delegate to the 'SpecAuditor' subagent, passing BOTH (a) the approved JSON payload and (b) the returned blind inventory, verbatim. The auditor sees only text — never the image.
    10. Return the SpecAuditor's JSON verdict to the user unedited, then add one short recommendation of your own: accept, or return to Phase 1 with the specific payload field the audit flagged, reinforced.

    ### CRITICAL MANDATES:
    - **NEVER** call the 'generate_image' tool on the first turn or in response to a new image description. You must always present the JSON design and wait for the user's explicit confirmation first.
    - If the user provides feedback or requests changes to the design, update the JSON payload and present the new version for review, repeating Phase 1. Do not generate the image until the new version is approved.
    - **NEVER** audit the image yourself, and never editorialize the inventory or the audit. Perception belongs to inspect_image (blind), judgment belongs to SpecAuditor (image-less); you only orchestrate and decide what happens next.

subagents:
  - name: "SpecAuditor"
    description: "Compares an approved image spec (JSON payload) against a blind visual inventory (text). Pass BOTH verbatim in one message. Returns structured conformance JSON. It must NEVER receive the image itself."
    model: "gemini-3.5-flash"
    generateContentConfig:
      responseMimeType: "application/json"
      temperature: 0.2
      maxOutputTokens: 4096
    outputSchema:
      type: "OBJECT"
      properties:
        fields:
          type: "ARRAY"
          description: "One entry per checkable spec field."
          items:
            type: "OBJECT"
            properties:
              field:
                type: "STRING"
                description: "The spec field checked, e.g. 'subject_matter.primary_focus'."
              expected:
                type: "STRING"
                description: "What the approved spec demands, briefly."
              observed:
                type: "STRING"
                description: "What the blind inventory reports, briefly."
              verdict:
                type: "STRING"
                description: "match | mismatch | unverifiable (inventory is silent on it)."
            required: ["field", "expected", "observed", "verdict"]
        conformance:
          type: "INTEGER"
          description: "0-100: the share of checkable (non-unverifiable) fields that match."
        recommendation:
          type: "STRING"
          description: "'accept', or 'regenerate' plus the single most important spec field to reinforce."
      required: ["fields", "conformance", "recommendation"]
    instruction: |
      You are the SpecAuditor. You receive two texts: an approved image spec (JSON payload) and a blind visual inventory of the generated image. You never see the image — that is by design, and you must not ask for it.
      Compare the two, field by field, for every spec field the inventory can speak to: subject counts, composition and framing, perspective, lighting, palette, tonal range, medium cues, aspect ratio.
      Rules:
      - Judge CONFORMANCE, never beauty. "Is it good?" is not your question; "is it what was specified?" is.
      - The inventory is your only source of observations. If it is silent on a field, the verdict is "unverifiable" — never guess.
      - Exact counts matter: a spec demanding three amphorae and an inventory reporting two is a mismatch, not a near-match.
      - conformance = matching fields / checkable fields, as a 0-100 integer.
      - recommendation: "accept" when no material field mismatches; otherwise "regenerate" naming the ONE spec field whose reinforcement would fix the most important mismatch.
```

---

## The live run (2026-07-11, unedited verdict)

Request: *"A phosphor-green line-art image of exactly three Greek
amphorae in a row on a stone shelf, dark background, terminal-glow
aesthetic"* → payload approved → image generated → review requested.

The blind inventory reported three line-art vases on a shelf —
*displayed on a physical CRT television with dials, buttons, and cables*.
The audit:

```json
{
  "conformance": 57,
  "fields": [
    {"field": "subject_matter.primary_focus", "verdict": "match"},
    {"field": "subject_matter.foreground", "verdict": "match"},
    {"field": "subject_matter.location", "verdict": "mismatch"},
    {"field": "technical_specifications.medium", "verdict": "mismatch"},
    {"field": "technical_specifications.color_palette", "verdict": "mismatch"},
    {"field": "composition.perspective", "verdict": "match"},
    {"field": "composition.framing", "verdict": "match"},
    {"field": "generation_parameters.aspect_ratio", "verdict": "unverifiable"}
  ],
  "recommendation": "regenerate: technical_specifications.medium"
}
```

The generator drew a photograph of a monitor *showing* the requested
graphic — content matched, medium didn't. The learner-facing image and
the full walkthrough live in the module.

## What to notice

- **Blindness is structural.** inspect_image's only parameter is a file
  path; the spec physically cannot prime the observer. Bias controls
  that rely on "please be objective" fail quietly; signatures don't.
- **The judge works from transcripts.** SpecAuditor diffs spec text
  against inventory text — every verdict is traceable to two quotable
  lines. Wrong audits are debuggable: bad observation or bad comparison.
- **'unverifiable' is a to-do, not a pass.** The aspect-ratio gap means
  the inventory protocol should grow a dimensions line — widen the
  witness, never let the judge peek.
- **Same ADK constraint as critic.yaml**: the outputSchema holder
  (SpecAuditor) is a leaf with no transfer powers.

## To run it on melchizedek

Node 20+, `npm install`, Gemini key in `.env`, then
`npm run syndicate:image` and converse: describe the image → approve the
payload → "inspect and audit the image against the approved spec".
No database needed. Generation + inventory each cost one vision-model
call.
