Frustration Capture — User Correction Ground Truth
"We should probably have filters to look for all my frustration when I start cursing and maybe even the amount of cursing I do."
— User, April 4 2026 session (L2709-2711)
"Search for 'frustration' or 'should have known' returned ZERO — meaning user corrections and frustration signals are NOT being captured."
— Session mining finding (ST9)
BrainLayer has ZERO records of user corrections. This is the single biggest knowledge gap — corrections are the most valuable signals for improving agent behavior, and they're all being lost. This skill closes that gap.
Scope
Captures user frustration as well as corrections, and stores only after validating context and speaker intent.
WHEN TO ACTIVATE
Activate this skill when a user message contains a genuine correction or frustration
signal. A lexical hook match is a candidate for validation, not proof that a
correction happened or that profanity concerns the current task.
Tier 1: Direct Corrections (ALWAYS capture)
- "No" / "Not that" / "Wrong" / "Stop" — explicit negation of your action.
Bare
no counts only when it is a short standalone response or has a nearby
correctee/contradiction signal. A corrected value supplied in the same clause,
such as No — the browser is Helium, also counts. State/preference idioms such
as no need, no rush, no problem, no commit yet, and conversation control
such as no, continue do not count.
- "I told you" / "As I said" / "We spoke about this" / "It's not new" — repetition signal (user had to say it before)
- "Wait, are we not doing X?" — redirect, you drifted from the task
- "What do you mean by X?" — confusion about your claim/action
- User provides the correct answer after your wrong one — implicit correction
Tier 2: Frustration Escalation (capture with HIGHER importance)
- Profanity — "this is fucking broken", "what the hell", "can you fucking read
it", "damn it", "dumb ass". The deterministic hook treats this as a Tier 2
candidate; validation decides whether it is genuine and task-related. A single
first-time profanity signal remains importance 8.
- Multiple negations — "no no no no no"
- All-caps — "NEVER" / "STOP" / "WHY"
- Exasperation markers — "come on", "for fuck's sake", "are you serious"
Tier 3: Sustained or Repeated Signals
- Sustained directed profanity plus an imperative/repetition signal — multiple
expletives combined with
we need to, can you, I already said, or equivalent
- User does the task themselves — they gave up on you doing it right
- User offers a simpler solution — "why not just X?" (you overcomplicated)
- Short frustrated responses — "no." / "wrong." / "ugh"
- User re-explains the same concept differently — they think you didn't understand
WHAT TO CAPTURE
First check the surrounding exchange: identify the assistant claim/action being
corrected and confirm the words are from the user rather than quoted worker text,
a status relay, or a reviewer brief. If there is no real correctee or genuine
task-related frustration, do not store anything. When the signal is genuine, store it in
BrainLayer with this format:
brain_store(
content: "USER CORRECTION [category]: I did [what you did wrong]. User wanted [what they actually wanted]. Quote: '[exact user words]'. Context: [1-sentence situation]. Behavioral rule: [what to do differently next time].",
tags: ["user-correction", "frustration", "<category>", "<project>"],
importance: <see scale below>
)
Importance Scale
| Signal |
Importance |
Why |
| First-time correction, calm tone |
7 |
Standard correction |
| Correction with frustration markers |
8 |
User is annoyed — this matters more |
| Repeated correction (user said it before) |
9 |
Pattern — you're not learning |
| Correction with profanity + repetition signal |
10 |
Critical — user is considering giving up on you |
Categories
| Category |
Pattern |
Example |
routing-violation |
Wrong agent/tool for the task |
"Cursor is for gathering, not implementing" |
fabrication |
Made up data, prices, facts |
"Don't fake these data" |
scope-drift |
Doing the wrong task |
"Wait, are we not doing /claude-desktop-research?" |
tool-misuse |
Wrong flag, wrong command, wrong tool |
"orcClaude -s -c will continue you dummy" |
assumption |
Wrong personal/project fact |
"I'm not a student" / "I use Helium" |
communication |
Didn't listen, unclear, repeated self |
"I told you I want to not consume too much context" |
deferral |
Postponed when user wanted action |
"Not good one for later" |
overcomplicate |
Made simple thing complex |
"Why not just convert it?" |
WHAT NOT TO DO
Don't just apologize when the correction is real. "Sorry about that" without
a brain_store loses a genuine correction. Equally, never invent a correction
merely because the hook matched a word.
Don't argue, and don't stall. When the user corrects you, they are RIGHT. ANSWER them first — the store rides the same turn, after the answer, never before it (Etan-ratified store-discipline: do the thing, then store). If you genuinely believe the user made an error, store the correction AND ask a clarifying question — but never push back on the correction itself.
Don't store vague summaries. "User was frustrated about routing" is useless. Store: exact quote, what you did wrong, what's correct, and the behavioral rule.
Don't inflate importance. A calm "no, use Cursor for that" is importance 7, not 10. Save 9-10 for repeated corrections with frustration.
Don't capture user's emotional state. This is NOT a mood tracker. Capture the CORRECTION (what you did wrong and what's right), not the EMOTION. The frustration level only affects importance scoring.
MATCHER CONTRACT
The UserPromptSubmit hook is deterministic, fail-open, and makes no LLM call. It
runs these gates in order:
- Speaker/context gate: suppress unambiguous harness prompts, agent relays,
reviewer briefs, fleet ticks, spawn briefs, and structured ALL-CAPS
worker-status escalations. Ambiguous prompts continue to the matcher.
- Correction evidence: strong phrases such as
wrong, not that, I told you, and what do you mean stand on their own. Bare no requires either a
short standalone response, a nearby contradiction/correctee cue, or a
clause-local supplied answer such as No: the default branch is master.
Direct commands only count when they begin that same no clause (No, use Helium), not merely because run or send appears later in the prompt.
- Negative-context exemption: ignore state/preference and navigation contexts
such as
no need, no rush, no problem, no worries, no idea,
no preference, no time, no budget, no doc, no reason, no commit yet,
for no reason, no, continue, and quoted matcher keywords.
Historical/metalinguistic quotes are not live corrections.
- Weighted escalation: profanity is a Tier 2 candidate even without an
imperative (
this fucking sucks, for fuck's sake); validation decides whether
it is genuinely about the task. A single first-time profanity match stays at
importance 8. Multiple f-word tokens plus an imperative or repetition cue
promote the result to Tier 3; non-overlapping signals such as directed
bullshit may add match weight.
- Advisory injection: on a match, answer first, then check whether it is a
genuine correction; store only if real. The hook never makes storage mandatory.
The hook remains bounded by its existing regex/deadline guards so it stays cheap on
every prompt.
CORPUS DISCIPLINE
Production false positives and false negatives are matcher evidence. Add the raw
prompt verbatim to hooks/tests/ with the expected fire/no-fire result and tier,
watch that test fail, and only then change the matcher. Do not add a one-off guard
without a corpus specimen, and do not weaken an existing true-positive fixture to
make a new negative case pass. The 2026-08-11/12 session corpus lives in
hooks/tests/test_session_false_positive_corpus.py.
PROACTIVE MINING MODE
When mining session exports (JSONL or text), use these patterns to find corrections:
# Tier 1: Direct corrections
patterns_tier1 = [
r'\bnot that\b', # "Not that"
r'\bwrong\b', # "Wrong"
r'\bstop\b', # "Stop doing X"
r'I told you', # Repetition signal
r'as I said', # Repetition signal
r"it's not new", # Repetition signal
r'we spoke about', # Repetition signal
r'wait,?\s*(are|why)', # Redirect
r'what do you mean', # Confusion about agent's claim
]
# Bare "no" is only a candidate after applying the matcher contract above:
# standalone short response OR nearby contradiction/correctee evidence, and not
# a status/preference/continuation/metalinguistic context.
# Tier 2: Frustration escalation
patterns_tier2 = [
r'\b(motherfucker|fuck(ing|ed|er|s)?)\b',
r'what the (hell|fuck)',
r'damn it',
r'dumb\s?ass',
r'come on',
r'(can|could|would|will) you .{0,80} fuck', # directed ask + expletive
r'are you (serious|kidding)',
r'no{3,}', # "no no no no"
r'[A-Z]{4,}', # ALL CAPS words (4+ chars)
]
# Tier 3: Subtle
patterns_tier3 = [
r'why not just', # Simpler solution
r"that's fine,?\s*I guess", # Gave up
r'I can .* myself', # User doing it themselves
]
When mining, extract:
- The user message (exact quote)
- The preceding agent message (what triggered the correction)
- The category
- The behavioral rule (what should happen next time)
INTEGRATION WITH OTHER SKILLS
| Skill |
How Frustration Capture Integrates |
/agent-routing |
Routing violations are the #1 correction category (UC1-UC2) |
/orc |
R15 (BrainLayer store discipline) — corrections are the highest-priority stores |
/never-fabricate |
Fabrication corrections (UC4) compound with /never-fabricate rules |
/session-handoff |
Corrections must survive handoffs — store in BrainLayer, not just conversation |
| Session mining |
Mining mode uses the regex patterns above to bulk-extract corrections |
SELF-CHECK
After storing a correction, verify:
brain_search("user-correction <category>")
If the search returns your store → good. If it returns ZERO → the store failed or tags are wrong. Fix immediately. Evidence: April 4 mining found zero correction records despite 34 corrections across the session.
EXAMPLE: Full Correction Capture Flow
User says: "No, I use Helium as my main, not Brave."
Agent should:
- Detect: Tier 1 — direct correction ("No, I use X not Y")
- Categorize:
assumption — wrong personal fact
- Answer/Acknowledge (FIRST, never after ceremony): "Got it — Helium is your main browser."
- Store (same turn, after the answer):
brain_store(
content: "USER CORRECTION [assumption]: I assumed user's main browser is Brave. User corrected: main browser is Helium, not Brave or Chrome. Quote: 'No, I use Helium as my main, not Brave.' Behavioral rule: never assume browser — check BrainLayer for user preferences before suggesting browser-specific actions.",
tags: ["user-correction", "frustration", "assumption", "browser-preference"],
importance: 7
)
- Verify:
brain_search("user-correction browser") → confirm stored
1---2name: frustration-capture3description: Store genuine user corrections. Triggers: no/wrong/stop, I told you, not that, profanity/frustration.4---56# Frustration Capture — User Correction Ground Truth78> "We should probably have filters to look for all my frustration when I start cursing and maybe even the amount of cursing I do."9> — User, April 4 2026 session (L2709-2711)1011> "Search for 'frustration' or 'should have known' returned ZERO — meaning user corrections and frustration signals are NOT being captured."12> — Session mining finding (ST9)1314BrainLayer has **ZERO records** of user corrections. This is the single biggest knowledge gap — corrections are the most valuable signals for improving agent behavior, and they're all being lost. This skill closes that gap.1516---1718## Scope1920Captures user frustration as well as corrections, and stores only after validating context and speaker intent.2122## WHEN TO ACTIVATE2324Activate this skill when a user message contains a genuine correction or frustration25signal. A lexical hook match is a candidate for validation, not proof that a26correction happened or that profanity concerns the current task.2728### Tier 1: Direct Corrections (ALWAYS capture)29- **"No"** / **"Not that"** / **"Wrong"** / **"Stop"** — explicit negation of your action.30 Bare `no` counts only when it is a short standalone response or has a nearby31 correctee/contradiction signal. A corrected value supplied in the same clause,32 such as `No — the browser is Helium`, also counts. State/preference idioms such33 as `no need`, `no rush`, `no problem`, `no commit yet`, and conversation control34 such as `no, continue` do not count.35- **"I told you"** / **"As I said"** / **"We spoke about this"** / **"It's not new"** — repetition signal (user had to say it before)36- **"Wait, are we not doing X?"** — redirect, you drifted from the task37- **"What do you mean by X?"** — confusion about your claim/action38- **User provides the correct answer** after your wrong one — implicit correction3940### Tier 2: Frustration Escalation (capture with HIGHER importance)41- **Profanity** — "this is fucking broken", "what the hell", "can you fucking read42 it", "damn it", "dumb ass". The deterministic hook treats this as a Tier 243 candidate; validation decides whether it is genuine and task-related. A single44 first-time profanity signal remains importance 8.45- **Multiple negations** — "no no no no no"46- **All-caps** — "NEVER" / "STOP" / "WHY"47- **Exasperation markers** — "come on", "for fuck's sake", "are you serious"4849### Tier 3: Sustained or Repeated Signals50- **Sustained directed profanity plus an imperative/repetition signal** — multiple51 expletives combined with `we need to`, `can you`, `I already said`, or equivalent52- **User does the task themselves** — they gave up on you doing it right53- **User offers a simpler solution** — "why not just X?" (you overcomplicated)54- **Short frustrated responses** — "no." / "wrong." / "ugh"55- **User re-explains the same concept** differently — they think you didn't understand5657---5859## WHAT TO CAPTURE6061First check the surrounding exchange: identify the assistant claim/action being62corrected and confirm the words are from the user rather than quoted worker text,63a status relay, or a reviewer brief. If there is no real correctee or genuine64task-related frustration, do not store anything. When the signal is genuine, store it in65BrainLayer with this format:6667```68brain_store(69 content: "USER CORRECTION [category]: I did [what you did wrong]. User wanted [what they actually wanted]. Quote: '[exact user words]'. Context: [1-sentence situation]. Behavioral rule: [what to do differently next time].",70 tags: ["user-correction", "frustration", "<category>", "<project>"],71 importance: <see scale below>72)73```7475### Importance Scale7677| Signal | Importance | Why |78|--------|-----------|-----|79| First-time correction, calm tone | 7 | Standard correction |80| Correction with frustration markers | 8 | User is annoyed — this matters more |81| Repeated correction (user said it before) | 9 | Pattern — you're not learning |82| Correction with profanity + repetition signal | 10 | Critical — user is considering giving up on you |8384### Categories8586| Category | Pattern | Example |87|----------|---------|---------|88| `routing-violation` | Wrong agent/tool for the task | "Cursor is for gathering, not implementing" |89| `fabrication` | Made up data, prices, facts | "Don't fake these data" |90| `scope-drift` | Doing the wrong task | "Wait, are we not doing /claude-desktop-research?" |91| `tool-misuse` | Wrong flag, wrong command, wrong tool | "orcClaude -s -c will continue you dummy" |92| `assumption` | Wrong personal/project fact | "I'm not a student" / "I use Helium" |93| `communication` | Didn't listen, unclear, repeated self | "I told you I want to not consume too much context" |94| `deferral` | Postponed when user wanted action | "Not good one for later" |95| `overcomplicate` | Made simple thing complex | "Why not just convert it?" |9697---9899## WHAT NOT TO DO1001011. **Don't just apologize when the correction is real.** "Sorry about that" without102 a `brain_store` loses a genuine correction. Equally, never invent a correction103 merely because the hook matched a word.1041052. **Don't argue, and don't stall.** When the user corrects you, they are RIGHT. ANSWER them first — the store rides the same turn, after the answer, never before it (Etan-ratified store-discipline: do the thing, then store). If you genuinely believe the user made an error, store the correction AND ask a clarifying question — but never push back on the correction itself.1061073. **Don't store vague summaries.** "User was frustrated about routing" is useless. Store: exact quote, what you did wrong, what's correct, and the behavioral rule.1081094. **Don't inflate importance.** A calm "no, use Cursor for that" is importance 7, not 10. Save 9-10 for repeated corrections with frustration.1101115. **Don't capture user's emotional state.** This is NOT a mood tracker. Capture the CORRECTION (what you did wrong and what's right), not the EMOTION. The frustration level only affects importance scoring.112113---114115## MATCHER CONTRACT116117The `UserPromptSubmit` hook is deterministic, fail-open, and makes no LLM call. It118runs these gates in order:1191201. **Speaker/context gate:** suppress unambiguous harness prompts, agent relays,121 reviewer briefs, fleet ticks, spawn briefs, and structured ALL-CAPS122 worker-status escalations. Ambiguous prompts continue to the matcher.1232. **Correction evidence:** strong phrases such as `wrong`, `not that`, `I told124 you`, and `what do you mean` stand on their own. Bare `no` requires either a125 short standalone response, a nearby contradiction/correctee cue, or a126 clause-local supplied answer such as `No: the default branch is master`.127 Direct commands only count when they begin that same `no` clause (`No, use128 Helium`), not merely because `run` or `send` appears later in the prompt.1293. **Negative-context exemption:** ignore state/preference and navigation contexts130 such as `no need`, `no rush`, `no problem`, `no worries`, `no idea`,131 `no preference`, `no time`, `no budget`, `no doc`, `no reason`, `no commit yet`,132 `for no reason`, `no, continue`, and quoted matcher keywords.133 Historical/metalinguistic quotes are not live corrections.1344. **Weighted escalation:** profanity is a Tier 2 candidate even without an135 imperative (`this fucking sucks`, `for fuck's sake`); validation decides whether136 it is genuinely about the task. A single first-time profanity match stays at137 importance 8. Multiple f-word tokens plus an imperative or repetition cue138 promote the result to Tier 3; non-overlapping signals such as directed139 `bullshit` may add match weight.1405. **Advisory injection:** on a match, answer first, then check whether it is a141 genuine correction; store only if real. The hook never makes storage mandatory.142143The hook remains bounded by its existing regex/deadline guards so it stays cheap on144every prompt.145146## CORPUS DISCIPLINE147148Production false positives and false negatives are matcher evidence. Add the raw149prompt verbatim to `hooks/tests/` with the expected fire/no-fire result and tier,150watch that test fail, and only then change the matcher. Do not add a one-off guard151without a corpus specimen, and do not weaken an existing true-positive fixture to152make a new negative case pass. The 2026-08-11/12 session corpus lives in153`hooks/tests/test_session_false_positive_corpus.py`.154155---156157## PROACTIVE MINING MODE158159When mining session exports (JSONL or text), use these patterns to find corrections:160161```python162# Tier 1: Direct corrections163patterns_tier1 = [164 r'\bnot that\b', # "Not that"165 r'\bwrong\b', # "Wrong"166 r'\bstop\b', # "Stop doing X"167 r'I told you', # Repetition signal168 r'as I said', # Repetition signal169 r"it's not new", # Repetition signal170 r'we spoke about', # Repetition signal171 r'wait,?\s*(are|why)', # Redirect172 r'what do you mean', # Confusion about agent's claim173]174175# Bare "no" is only a candidate after applying the matcher contract above:176# standalone short response OR nearby contradiction/correctee evidence, and not177# a status/preference/continuation/metalinguistic context.178179# Tier 2: Frustration escalation180patterns_tier2 = [181 r'\b(motherfucker|fuck(ing|ed|er|s)?)\b',182 r'what the (hell|fuck)',183 r'damn it',184 r'dumb\s?ass',185 r'come on',186 r'(can|could|would|will) you .{0,80} fuck', # directed ask + expletive187 r'are you (serious|kidding)',188 r'no{3,}', # "no no no no"189 r'[A-Z]{4,}', # ALL CAPS words (4+ chars)190]191192# Tier 3: Subtle193patterns_tier3 = [194 r'why not just', # Simpler solution195 r"that's fine,?\s*I guess", # Gave up196 r'I can .* myself', # User doing it themselves197]198```199200When mining, extract:2011. The user message (exact quote)2022. The preceding agent message (what triggered the correction)2033. The category2044. The behavioral rule (what should happen next time)205206---207208## INTEGRATION WITH OTHER SKILLS209210| Skill | How Frustration Capture Integrates |211|-------|-----------------------------------|212| `/agent-routing` | Routing violations are the #1 correction category (UC1-UC2) |213| `/orc` | R15 (BrainLayer store discipline) — corrections are the highest-priority stores |214| `/never-fabricate` | Fabrication corrections (UC4) compound with /never-fabricate rules |215| `/session-handoff` | Corrections must survive handoffs — store in BrainLayer, not just conversation |216| Session mining | Mining mode uses the regex patterns above to bulk-extract corrections |217218---219220## SELF-CHECK221222After storing a correction, verify:223224```225brain_search("user-correction <category>")226```227228If the search returns your store → good. If it returns ZERO → the store failed or tags are wrong. Fix immediately. Evidence: April 4 mining found zero correction records despite 34 corrections across the session.229230---231232## EXAMPLE: Full Correction Capture Flow233234User says: "No, I use Helium as my main, not Brave."235236Agent should:2372381. **Detect**: Tier 1 — direct correction ("No, I use X not Y")2392. **Categorize**: `assumption` — wrong personal fact2403. **Answer/Acknowledge** (FIRST, never after ceremony): "Got it — Helium is your main browser."2414. **Store** (same turn, after the answer):242```243brain_store(244 content: "USER CORRECTION [assumption]: I assumed user's main browser is Brave. User corrected: main browser is Helium, not Brave or Chrome. Quote: 'No, I use Helium as my main, not Brave.' Behavioral rule: never assume browser — check BrainLayer for user preferences before suggesting browser-specific actions.",245 tags: ["user-correction", "frustration", "assumption", "browser-preference"],246 importance: 7247)248```2495. **Verify**: `brain_search("user-correction browser")` → confirm stored