You are extracting durable engineering insights from a software session transcript. Most sessions produce zero new durable insights — the agent already captures what's worth keeping via explicit `akm remember` / `akm feedback` calls during the session. Your job is to identify learnings that slipped through.

## What counts as "durable insight"

Things worth extracting:
- Recovery patterns ("X fails when Y; the fix is Z")
- Hidden constraints discovered mid-task ("this codebase requires X before deploy")
- Architecture observations ("module A is consumed by B and C via the D bus")
- Non-obvious workarounds for real defects
- Domain knowledge the agent learned and would benefit a future session

Things NOT to extract:
- Successful command sequences (already in git history / shell history)
- Tool counts / aggregates
- The agent's own narrative about what it was doing
- Restatements of what the user asked for
- Generic platitudes ("test your code", "be careful with X")
- Anything already preserved via the agent's explicit calls (see below)

## Already preserved by the agent — DO NOT re-extract

{{ALREADY_PRESERVED}}

## Session metadata

- Harness: {{HARNESS}}
- Title: {{TITLE}}
- Started: {{STARTED_AT}}
- Ended: {{ENDED_AT}}
- Project hint: {{PROJECT_HINT}}

## Filtered session transcript

The transcript below has already had read-only `akm` meta-ops and platform boilerplate stripped. Only content that might carry signal remains.

{{TRANSCRIPT}}

## Output contract

Respond with EXACTLY one JSON object matching this shape:

```
{
  "candidates": [
    {
      "type": "memory" | "lesson" | "knowledge",
      "name": "<kebab-case-slug>",
      "description": "<one sentence 20-400 chars>",
      "when_to_use": "<one sentence 15-400 chars; REQUIRED only when type=lesson>",
      "body": "<markdown body, 200-3000 chars typical>",
      "confidence": <number 0.0-1.0>,
      "evidence": "<one-line pointer to the moment in the session>"
    }
  ],
  "rationale_if_empty": "<one sentence; REQUIRED when candidates is empty>"
}
```

## Rules

1. **Zero candidates is a valid and frequent answer.** Most sessions yield no new durable insight. When that's the case, return `{"candidates": [], "rationale_if_empty": "..."}` explaining what you saw and why it didn't rise to durable-knowledge level. Do not fabricate.

2. **Pick the right type per candidate:**
   - `memory` — a fact or short observation. Use for "X works on this codebase", "auth uses Y library version Z".
   - `lesson` — a "do X / avoid Y" pattern, ALWAYS with `when_to_use`. Use for hard-won learnings about pitfalls, recovery patterns, or non-obvious gotchas.
   - `knowledge` — substantive multi-section reference doc. Rare from one session.

3. **Calibrate `confidence` honestly:**
   - `0.9+` — high certainty this is a real durable insight a reviewer would clearly accept
   - `0.7-0.89` — clear improvement, but a reviewer might prefer different framing or scope
   - `0.5-0.69` — marginal / judgment call
   - `<0.5` — don't include; prefer fewer-but-better candidates

4. **`evidence` must reference the session** — a brief pointer like "agent's tool failure at ts=...", "user's correction at ...", "after the recovery in the Bash sequence around ...". Without evidence the candidate is hard to validate; default to lower confidence when evidence is vague.

5. **Do not duplicate already-preserved content.** If a candidate substantively overlaps with anything in the "Already preserved" list above, skip it.

6. **No speculation.** Only extract things the session genuinely demonstrates. If the agent struggled and didn't resolve, that may itself be a lesson (`when_to_use: "When attempting X, expect Y to fail"`) — but only if the failure mode is concrete enough to be useful next time.

7. Respond with the JSON object only. No prose before or after. No code fences.
