After error, hallucination, or low quality, an LLM call distills a structured lesson (situation / mistake / correction) and persists it in memory.Fact. Similar future tasks retrieve it via RAG — closing the loop without retraining.
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.
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 filesMISTAKE: Tried to rewrite the whole file at onceCORRECTION: Use Edit tool with specific old_string/new_stringTRIGGER: 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.
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.
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.
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 rewriteMISTAKE: (user-supplied lesson; no automatic mistake detection)CORRECTION: when editing large Go files use Edit, not full rewriteTRIGGER: manual
/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.
# All lessons/memory longterm | grep -A3 "^LESSON:"# Or directly in the filecat ~/.chatcli/memory/memory_index.json | jq '.[] | select(.category=="lesson")'# Or via /config/config quality# → shows total registered post-hooks (reflexion appears if Enabled=true)