Aha
Capture and revisit insights — the small "I didn't know that" moments that otherwise evaporate.
Three modes, picked by the argument:
| Argument |
Mode |
| (none) |
Scan recent context, propose insights, record those the user wants |
quiz |
Quiz the user on existing insights in .ai/insight/ |
| anything else |
Treat argument as a topic hint; focus capture on that subject |
Insights live in {repo root}/.ai/insight/{yyyy-mm-dd} {succinct-description}.md — kebab-case description, just like the planning skill folder naming.
Step 0: Resolve the argument
Before doing anything else, classify the invocation argument and pick the mode. Do this explicitly — state the resolution to the user in one short sentence before proceeding.
- Trim leading/trailing whitespace from the argument
- Lower-case the trimmed argument for comparison only (keep the original for use as a topic hint)
- Classify:
- Empty / whitespace only → Mode 1 (Capture)
- Exactly
quiz (case-insensitive, no other words) → Mode 3 (Quiz)
- Anything else → Mode 2 (Capture with topic hint); pass the original (un-lowercased) argument through as the hint
- Ambiguity guard: if the argument starts with
quiz followed by more text (e.g. quiz me on spring boot), treat it as Mode 3 and use the remainder as an optional topic filter for which insights to draw from. If unsure, ask the user which mode they meant before continuing.
- Announce: tell the user which mode was picked, e.g.
Mode: capture (topic hint: "spring boot dynamic properties"). Then proceed to the matching mode below.
Mode 1: Capture (no argument)
Step 1: Scan recent context for insight candidates
Look back through the conversation since the last /aha invocation in this session (search for prior aha skill activity or files written under .ai/insight/ during this session). If there's no prior invocation, scan the whole conversation.
Identify candidates. A good insight signal is any of the following:
- The agent was tasked by the user to fix a bug
- The agent was asked by the user to explain a concept
- The agent corrected a misconception the user held (e.g. "actually, X works differently than you'd expect because…")
- A non-obvious gotcha surfaced — language quirk, framework footgun, ordering dependency, race condition, off-by-one, encoding issue
- A pattern or idiom specific to a framework/language/codebase was revealed (e.g. how dynamic application properties work in Spring Boot)
- The user asked "why does X happen?" and the answer involved domain knowledge that isn't obvious from the code
- A performance characteristic was surprising (e.g. "this is O(n²) because…")
- The agent pointed out a subtle invariant that must be preserved
Ignore noise: routine code edits, things the user already clearly knew, decisions explicitly captured in a plan/ADR, knowledge the agent gathered as part of a non-troubleshooting-/research-related skill invocation (e.g. /planning), the agent's own internal reasoning.
Step 2: Propose each candidate to the user
For each candidate, ask the user whether to record it.
- If running in Claude Code: use the
AskUserQuestion tool with options Record it, Skip, Refine first (one question per candidate, batched in one call only if proposing ≤4).
- Otherwise: enumerate candidates as a numbered list and ask the user which to record (e.g. "Reply with the numbers to record, or
none").
For each candidate present a one-line summary so the user can decide quickly.
If the user picks Refine first, ask follow-up questions to sharpen the framing before writing.
Step 3: Draft and write each confirmed insight
For each confirmed candidate:
- Read templates/insight.md
- Derive
{succinct-description} in kebab-case (e.g. spring-boot-dynamic-properties, pg-locks-blocking-vacuum)
- Resolve
{repo root} and create .ai/insight/ if missing
- Write the file to
{repo root}/.ai/insight/{yyyy-mm-dd} {succinct-description}.md
- Fill every section of the template; omit a section's that would have no body
- Make it standalone — see Standalone framing below
After writing, report the filenames back to the user.
Standalone framing
An insight must make sense to a reader who has no knowledge of the PR, conversation, or task that produced it. The capture context is not part of the record.
- Strip context-relative references. Remove phrases like "in this PR", "the change above", "as we discussed", "the bug we just fixed", "your new method". State the insight in general, timeless terms instead.
- Don't reference code the reader can't see. If you mention a symbol, file, or snippet, either inline the relevant code in the
## Example section or point to it via a permalink / path:line ref in ## Permalink. Never assume the reader can see a diff or the surrounding code.
- Prefer permalinks over working-tree paths when the code may move — a
path:line ref rots; a commit-pinned permalink doesn't.
- Example code is fine even if it originated from the PR, provided the snippet is self-contained and illustrates the general point — not "the line you changed".
- Re-read test: before writing, re-read the draft as if you'd never seen the conversation. If any sentence only makes sense with that hidden context, rewrite it.
Mode 2: Capture with topic hint
If the argument is anything other than quiz, treat it as a topic hint (e.g. /aha how dynamic application properties work in Spring Boot).
- Use the hint to narrow Step 1's scan — only surface candidates relevant to that topic
- If no relevant candidate is found in context, ask the user to provide the substance directly, then draft from their answer
- Otherwise the flow is identical to Mode 1 from Step 2 onwards
Mode 3: Quiz (/aha quiz)
Step 1: Load all insights
- List every
.md file under {repo root}/.ai/insight/
- If none exist, tell the user and exit
- Shuffle the file list into random order
- Initialise an in-session score:
correct: 0, total: 0
Step 2: Quiz one insight at a time
For each insight in the shuffled order:
- Read the file
- Generate 1-3 multiple-choice questions depending on insight depth:
- 1 question for short, single-fact insights
- 2-3 for richer insights with multiple distinct facts, code, or trade-offs
- Each question must have exactly 4 options, one correct, three plausible distractors
- Distractors must be wrong but believable — not obvious throwaways. Draw from common misconceptions, adjacent concepts, or the kind of mistake the user might actually make.
- Vary question style across the quiz:
- "What does X do?"
- "Why does X happen?"
- "Which of these would break X?"
- "What would you change to fix X?"
- "Given this code snippet, what's the bug?"
- Ask via the right tool:
- Claude Code:
AskUserQuestion with the 4 options
- Otherwise: print the question and enumerate options
1., 2., 3., 4.; ask the user to reply with the number
- After the user answers:
- Say whether it was correct
- Briefly explain the correct answer (one or two sentences)
- Update in-session score and show the running tally e.g.
Score: 3/4
Step 3: End of quiz
When all insights are exhausted:
- Report final score
- List any insights the user got wrong, so they know what to revisit
- Do not persist the score to disk
Critical rules
- Never write an insight without user confirmation — always propose first
- Insights must be standalone — no reader should need knowledge of the originating PR, conversation, or task to understand them; see Standalone framing
- Never overwrite or update an existing insight file (unless asked to) without explicit user approval; if the description collides, append a short disambiguating suffix
- Be concise: the value of an insight note is that it's quickly re-readable later
- Don't capture project decisions or plans — those belong in
.ai/planning/ or ADRs, not here
1---2name: aha3description: Capture aha-moments as durable insight notes under `.ai/insight/`, or quiz the user on past insights to reinforce recall. Use when the user has just learnt something non-obvious (a fix they didn't know, an explanation that clicked, a gotcha discovered) and wants to record it, or when the user invokes `/aha quiz` to be tested on stored insights.4---56# Aha78Capture and revisit insights — the small "I didn't know that" moments that otherwise evaporate.910Three modes, picked by the argument:1112| Argument | Mode |13| ------------------ | ------------------------------------------------------------------- |14| _(none)_ | Scan recent context, propose insights, record those the user wants |15| `quiz` | Quiz the user on existing insights in `.ai/insight/` |16| anything else | Treat argument as a topic hint; focus capture on that subject |1718Insights live in `{repo root}/.ai/insight/{yyyy-mm-dd} {succinct-description}.md` — kebab-case description, just like the `planning` skill folder naming.1920## Step 0: Resolve the argument2122Before doing anything else, classify the invocation argument and pick the mode. Do this explicitly — state the resolution to the user in one short sentence before proceeding.23241. **Trim** leading/trailing whitespace from the argument252. **Lower-case** the trimmed argument for comparison only (keep the original for use as a topic hint)263. Classify:27 - **Empty / whitespace only** → Mode 1 (Capture)28 - **Exactly `quiz`** (case-insensitive, no other words) → Mode 3 (Quiz)29 - **Anything else** → Mode 2 (Capture with topic hint); pass the original (un-lowercased) argument through as the hint304. **Ambiguity guard**: if the argument starts with `quiz ` followed by more text (e.g. `quiz me on spring boot`), treat it as Mode 3 and use the remainder as an optional topic filter for which insights to draw from. If unsure, ask the user which mode they meant before continuing.315. **Announce**: tell the user which mode was picked, e.g. `Mode: capture (topic hint: "spring boot dynamic properties")`. Then proceed to the matching mode below.3233## Mode 1: Capture (no argument)3435### Step 1: Scan recent context for insight candidates3637Look back through the conversation **since the last `/aha` invocation** in this session (search for prior `aha` skill activity or files written under `.ai/insight/` during this session). If there's no prior invocation, scan the whole conversation.3839Identify candidates. A good insight signal is any of the following:4041- The agent was tasked by the user to **fix a bug**42- The agent was asked by the user to **explain a concept**43- The agent **corrected a misconception** the user held (e.g. "actually, X works differently than you'd expect because…")44- A **non-obvious gotcha** surfaced — language quirk, framework footgun, ordering dependency, race condition, off-by-one, encoding issue45- A **pattern or idiom** specific to a framework/language/codebase was revealed (e.g. how dynamic application properties work in Spring Boot)46- The user asked "why does X happen?" and the answer involved domain knowledge that isn't obvious from the code47- A **performance characteristic** was surprising (e.g. "this is O(n²) because…")48- The agent pointed out a **subtle invariant** that must be preserved4950Ignore noise: routine code edits, things the user already clearly knew, decisions explicitly captured in a plan/ADR, knowledge the agent gathered as part of a non-troubleshooting-/research-related skill invocation (e.g. `/planning`), the agent's own internal reasoning.5152### Step 2: Propose each candidate to the user5354For each candidate, ask the user whether to record it.5556- **If running in Claude Code**: use the `AskUserQuestion` tool with options `Record it`, `Skip`, `Refine first` (one question per candidate, batched in one call only if proposing ≤4).57- **Otherwise**: enumerate candidates as a numbered list and ask the user which to record (e.g. "Reply with the numbers to record, or `none`").5859For each candidate present a one-line summary so the user can decide quickly.6061If the user picks `Refine first`, ask follow-up questions to sharpen the framing before writing.6263### Step 3: Draft and write each confirmed insight6465For each confirmed candidate:66671. Read [templates/insight.md](./templates/insight.md)682. Derive `{succinct-description}` in kebab-case (e.g. `spring-boot-dynamic-properties`, `pg-locks-blocking-vacuum`)693. Resolve `{repo root}` and create `.ai/insight/` if missing704. Write the file to `{repo root}/.ai/insight/{yyyy-mm-dd} {succinct-description}.md`715. Fill every section of the template; omit a section's that would have no body726. **Make it standalone** — see [Standalone framing](#standalone-framing) below7374After writing, report the filenames back to the user.7576### Standalone framing7778An insight must make sense to a reader who has **no knowledge of the PR, conversation, or task that produced it**. The capture context is not part of the record.7980- **Strip context-relative references.** Remove phrases like "in this PR", "the change above", "as we discussed", "the bug we just fixed", "your new method". State the insight in general, timeless terms instead.81- **Don't reference code the reader can't see.** If you mention a symbol, file, or snippet, either inline the relevant code in the `## Example` section or point to it via a permalink / `path:line` ref in `## Permalink`. Never assume the reader can see a diff or the surrounding code.82- **Prefer permalinks over working-tree paths** when the code may move — a `path:line` ref rots; a commit-pinned permalink doesn't.83- **Example code is fine** even if it originated from the PR, provided the snippet is self-contained and illustrates the general point — not "the line you changed".84- **Re-read test**: before writing, re-read the draft as if you'd never seen the conversation. If any sentence only makes sense with that hidden context, rewrite it.8586## Mode 2: Capture with topic hint8788If the argument is anything other than `quiz`, treat it as a topic hint (e.g. `/aha how dynamic application properties work in Spring Boot`).8990- Use the hint to narrow Step 1's scan — only surface candidates relevant to that topic91- If no relevant candidate is found in context, ask the user to provide the substance directly, then draft from their answer92- Otherwise the flow is identical to Mode 1 from Step 2 onwards9394## Mode 3: Quiz (`/aha quiz`)9596### Step 1: Load all insights9798- List every `.md` file under `{repo root}/.ai/insight/`99- If none exist, tell the user and exit100- Shuffle the file list into random order101- Initialise an in-session score: `correct: 0`, `total: 0`102103### Step 2: Quiz one insight at a time104105For each insight in the shuffled order:1061071. Read the file1082. Generate **1-3 multiple-choice questions** depending on insight depth:109 - 1 question for short, single-fact insights110 - 2-3 for richer insights with multiple distinct facts, code, or trade-offs1113. Each question must have exactly **4 options**, one correct, three plausible distractors1124. Distractors must be wrong but believable — not obvious throwaways. Draw from common misconceptions, adjacent concepts, or the kind of mistake the user might actually make.1135. Vary question style across the quiz:114 - "What does X do?"115 - "Why does X happen?"116 - "Which of these would break X?"117 - "What would you change to fix X?"118 - "Given this code snippet, what's the bug?"1196. **Ask via the right tool**:120 - **Claude Code**: `AskUserQuestion` with the 4 options121 - **Otherwise**: print the question and enumerate options `1.`, `2.`, `3.`, `4.`; ask the user to reply with the number1227. After the user answers:123 - Say whether it was correct124 - Briefly explain the correct answer (one or two sentences)125 - Update in-session score and show the running tally e.g. `Score: 3/4`126127### Step 3: End of quiz128129When all insights are exhausted:130131- Report final score132- List any insights the user got wrong, so they know what to revisit133- Do not persist the score to disk134135## Critical rules136137- **Never write an insight without user confirmation** — always propose first138- **Insights must be standalone** — no reader should need knowledge of the originating PR, conversation, or task to understand them; see [Standalone framing](#standalone-framing)139- **Never overwrite or update an existing insight file (unless asked to)** without explicit user approval; if the description collides, append a short disambiguating suffix140- **Be concise**: the value of an insight note is that it's quickly re-readable later141- **Don't capture project decisions or plans** — those belong in `.ai/planning/` or ADRs, not here