# The Critic Review Workflow — full syndicate definition + live run

The complete, verbatim YAML for melchizedek's Drafter → Critic review
loop: a quality bar encoded as a machine-checkable confidence threshold.
Reference specimen for curriculum module 03 (Testing & refining an
agentic workflow) at
https://lyceumagents.com/curriculum/testing-and-refinement/

Portable: rebuild it in any framework with (1) one agent that can call
two others, (2) structured JSON output on the reviewer, and (3) an
instruction that branches on a parsed field. The design decisions worth
stealing are the separation (the maker never grades the making), the
structured verdict, the threshold, and the round cap.

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

---

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

```yaml
syndicate_name: "Critic Review Workflow"

# WHY this structure: The ADK enforces that outputSchema cannot co-exist with
# agent transfer (AgentTool) on the same agent. If the orchestrator has both,
# the ADK deadlocks it. Solution: the orchestrator is a plain sequencer that
# routes Drafter → Critic, and the CriticAgent (a leaf with no tools/transfers)
# owns the outputSchema for structured JSON production.
#
# WHY multi-turn internal looping:
#   The ADK's runAsync keeps executing within a single user turn as long as the
#   orchestrator continues to call tools rather than producing a final response.
#   By instructing the orchestrator to inspect the CriticAgent's confidence score
#   and re-delegate when it's below a threshold, the syndicate autonomously
#   refines answers through multiple Drafter→Critic passes — all within one
#   user-facing turn — before surfacing the final result.

orchestrator:
  name: "ReviewOrchestrator"
  model: "gemini-3.5-flash"
  instruction: |
    You coordinate an iterative review process between a Drafter and a Critic.
    Your goal is to ensure only HIGH-CONFIDENCE answers reach the user.

    Follow these steps EXACTLY:

    1. Delegate the user's question to DrafterAgent to get an initial answer.
    2. Take the DrafterAgent's full response and delegate it to CriticAgent for review.
    3. Parse the CriticAgent's JSON response. It contains "message" and "confidence".
    4. **CONFIDENCE CHECK** — this is the critical decision point:
       - If confidence >= 85: Return the CriticAgent's full JSON directly to the user. You are done.
       - If confidence < 85: The answer is NOT good enough. You MUST loop:
         a. Send the CriticAgent's feedback BACK to DrafterAgent with specific instructions
            on what to improve (cite the Critic's concerns).
         b. Take the DrafterAgent's revised answer and send it to CriticAgent again.
         c. Repeat from step 4.
    5. You may loop up to 3 times maximum. After 3 rounds, return whatever the
       CriticAgent's latest response is, regardless of confidence.
    6. Always return the raw JSON from CriticAgent as your final output. Do NOT paraphrase it.

subagents:
  - name: "DrafterAgent"
    model: "gemini-3.5-flash"
    description: "Creates comprehensive initial draft answers for any user query. On subsequent rounds, revises its draft based on Critic feedback."
    instruction: |
      You are the Drafter. When given a query, produce a thorough initial answer.
      Focus on gathering all necessary facts and providing a complete response.
      If you receive feedback from the Critic about a previous draft, carefully address
      every concern raised and produce an improved, more accurate revision.

  - name: "CriticAgent"
    model: "gemini-3.5-flash"
    description: "Reviews a draft answer for accuracy and returns a structured JSON with the refined message and a confidence score. Low scores trigger re-drafting."
    generateContentConfig:
      responseMimeType: "application/json"
    outputSchema:
      type: "OBJECT"
      properties:
        message:
          type: "STRING"
          description: "The final, improved and fact-checked response."
        confidence:
          type: "INTEGER"
          description: "A confidence score from 0 to 100 for the accuracy of the final message. Score below 85 means the answer needs improvement."
      required: ["message", "confidence"]
    instruction: |
      You are the Critic. You receive a draft answer from the Drafter.
      Review it rigorously for accuracy, clarity, completeness, and logical soundness.
      Be honest and precise with your confidence score:
      - 90-100: Excellent, factually verified, well-structured
      - 70-89: Good but has minor gaps or could be clearer
      - Below 70: Significant issues — factual errors, incomplete, or misleading
      Output a JSON object with:
      - "message": your refined and polished version of the answer
      - "confidence": an integer from 0 to 100 representing your confidence in accuracy
```

---

## One live run (2026-07-11, gemini-3.5-flash, unedited)

**You** › In two sentences, why did the Library of Alexandria decline?

**ReviewOrchestrator** › (DrafterAgent → CriticAgent, one round)

```json
{
  "confidence": 98,
  "message": "Rather than suffering a single catastrophic fire, the Great Library of Alexandria declined gradually over centuries due to dwindling institutional support, shifting intellectual centers, and accidental damage from conflicts like Julius Caesar's siege. This decline was compounded by civil unrest, religious decrees, and political instability under Roman rule, which eventually led to the complete dispersal of its legendary collection."
}
```

An honest footnote: we provoked this syndicate three times — a normal
question, a false-premise question ("explain how the Antikythera
mechanism used steam power"), and a mathematically impossible request
("list exactly 12 primes strictly between 100 and 150"). The drafter
survived all three in a single round; the false premise was corrected,
the impossibility was proven (there are 10 such primes). With strong
models the loop is insurance, not a crutch — the gate mostly stays green,
and you keep it anyway, because the day it goes red is the day it earns
its keep.

---

## What to notice

- **The comment block is the war story.** outputSchema cannot co-exist
  with agent transfer in the ADK — the deadlock was discovered by
  testing, and the fix was architectural: the schema-holding CriticAgent
  is a leaf with no transfer powers. Constraints found by testing become
  documented design.
- **The gate is one parsed integer.** "If confidence >= 85: return. If
  < 85: loop, citing the Critic's concerns." Judgment became executable
  the moment it became a field.
- **The cap is a cost bound.** Three rounds maximum, then ship the
  latest verdict, score attached. Every quality loop needs an exit that
  doesn't depend on agreement.
- **Verbatim hand-back.** The orchestrator must return the Critic's raw
  JSON — a paraphrasing middleman would corrupt the only signal the
  caller can act on.

## To run it on melchizedek

Node 20+, `npm install`, Gemini key in `.env`, then:
`npm run syndicate:critic -- "your question"`.
Watch the tool-call lines: one Drafter→Critic round on easy questions;
feed it something treacherous and read the confidence.
