Skip to main content
Reflexion closes the learning loop: when an agent fails or produces low-quality output, instead of losing the experience, the pipeline generates a structured Lesson and persists it to long-term memory. On the next similar task, that lesson naturally surfaces via RAG+HyDE.
Reflexion is the only post-hook on by default — because it only fires in exceptional conditions (error, discrepancy) and the lesson generator runs in a detached goroutine, never blocking the user turn.

What is a Lesson

A Lesson is a four-line record:
type Lesson struct {
    Situation  string   // "When editing large Go files..."
    Mistake    string   // "Tried to rewrite the whole file at once"
    Correction string   // "Use Edit tool with specific old_string/new_string"
    Tags       []string // ["go", "edit-file", "large-file", "reflexion"]
    Trigger    string   // "error" | "hallucination" | "low_quality" | "manual"
    CreatedAt  time.Time
}
When persisted as memory.Fact, Content becomes:
LESSON: When editing large Go files
MISTAKE: Tried to rewrite the whole file at once
CORRECTION: Use Edit tool with specific old_string/new_string
TRIGGER: error
The Fact category is lesson and tags include reflexion + trigger:<x> + domain-specific tags. This enables precise queries: “show me all lessons about edit-file” becomes a regular memory search.

Four triggers

if cfg.OnError && result.Error != nil {
    return "error"
}
The worker returned Error != nil. Examples: timeout, invalid tool call, provider crash. Default: ON.

Async flow

1

PostRun is called in the pipeline

ReflexionHook.PostRun(ctx, hc, result) inspects result.Metadata + result.Error to decide the trigger.
2

If trigger matched, spawn goroutine

go h.runReflexion(context.Background(), req)
return nil  // PostRun returns immediately
Detached context on purpose: the turn’s ctx will be cancelled when the response reaches the user, but we want the lesson generated anyway.
3

GenerateLesson via LLM

The LLM receives system prompt + task + attempt + outcome, and emits XML-like blocks (<situation>, <mistake>, <correction>, <tags>, or <skip> if no useful lesson).
4

Parse + persist

parseLesson validates that at least situation and correction are present. If <skip>nothing actionable</skip>, returns nil without persisting.
5

memory.Facts.AddFactWithSource

Persists in ~/.chatcli/memory/memory_index.json with category=lesson and tags including the current workspace as source.

Lesson generator protocol

The system prompt instructs the model to be general, not one-off:
Rules:
- A "lesson" must be GENERAL enough to apply next time a similar task
  comes up — not one-off and not a play-by-play.
- If there is genuinely nothing to learn (e.g. the task was trivial and
  the failure was a transient network blip), reply with exactly:
  <skip>nothing actionable</skip>
- Otherwise emit ALL of the following blocks. Keep each to ONE line.
- "tags" is a comma-separated list of 2-5 short keywords (lowercase,
  hyphenated if needed) that future similar tasks will likely contain.

OUTPUT:
<situation>brief description of when this lesson applies</situation>
<mistake>what went wrong this time</mistake>
<correction>what to do differently next time</correction>
<tags>tag1, tag2, tag3</tags>
The <skip> block exists precisely to avoid memory pollution with “lessons” from transient failures. The model can refuse to generate a lesson at zero persistence cost.

/reflect — manual path without LLM

When you know the lesson and don’t need an LLM distilling:
/reflect when editing large Go files use Edit, not full rewrite
Goes straight into memory.Fact:
LESSON: when editing large Go files use Edit, not full rewrite
MISTAKE: (user-supplied lesson; no automatic mistake detection)
CORRECTION: when editing large Go files use Edit, not full rewrite
TRIGGER: manual
Generated tags: ["reflexion", "trigger:manual", "user-supplied"].
The manual path does not make an LLM call — it’s cheap, synchronous, and ideal for capturing learnings during a session.

How the lesson “comes back”

Once persisted, the lesson is a regular fact in the index. It surfaces via:
  1. Hint-based retrieval: if the next task mentions keywords in Tags, the relevance-based scorer surfaces it.
  2. HyDE amplifies: with CHATCLI_QUALITY_HYDE_ENABLED=true, the generated hypothesis covers similar concepts, increasing match chance.
  3. Vector search: with embeddings configured, the lesson is searched by cosine proximity.
The next turn’s system prompt contains the ## Long-term Memory section with the lesson text, and the model has all the cues to not repeat the mistake.

Environment variables

Env varDefaultWhat it does
CHATCLI_QUALITY_REFLEXION_ENABLEDtrueMaster switch
CHATCLI_QUALITY_REFLEXION_ON_ERRORtrueFire on tool error
CHATCLI_QUALITY_REFLEXION_ON_HALLUCINATIONtrueFire on verified_with_discrepancy
CHATCLI_QUALITY_REFLEXION_ON_LOW_QUALITYfalseFire on refine_low_quality
CHATCLI_QUALITY_REFLEXION_PERSISTtrueWrite to memory.Fact (false = log-only)

Full cycle example

1

User asks for a task that fails

/coder refactor pkg/engine to extract Close method
2

CoderAgent tries full rewrite

File has 2000 lines, provider responds with timeout.
3

PostRun detects result.Error != nil

OnError trigger matched.
4

goroutine: GenerateLesson

Model emits:
<situation>Refactoring large Go files (>1000 lines)</situation>
<mistake>Attempted full rewrite via @coder write</mistake>
<correction>Use @coder patch or Edit tool for surgical changes</correction>
<tags>go, refactor, large-file, edit-tool</tags>
5

Persists in memory.Fact

Category=lesson, workspace=current project.
6

Next week, user asks for a similar refactor

/coder refactor pkg/auth/manager.go split into smaller files
7

RAG+HyDE brings the lesson

Tags refactor + large-file match. Lesson appears in the system prompt.
8

Coder picks the right approach from the start

Emits multiple @coder patch instead of write. Task done without timeout.

Inspect stored lessons

# All lessons
/memory longterm | grep -A3 "^LESSON:"

# Or directly in the file
cat ~/.chatcli/memory/memory_index.json | jq '.[] | select(.category=="lesson")'

# Or via /config
/config quality
# → shows total registered post-hooks (reflexion appears if Enabled=true)

See also

#4 RAG + HyDE

How lessons are retrieved in future tasks via semantic retrieval.

#6 CoVe

The verifier generates the verified_with_discrepancy signal that Reflexion consumes.

Bootstrap Memory

The layer underneath: how memory.Fact is populated and maintained.

Memory Commands

/memory load, /memory show, /memory longterm.