In one of The Wire’s most famous scenes, one that could be taught in a linguistics class, Bunk and McNulty reconstruct a crime scene for almost four minutes saying nothing but “fuck” and its variations. They pace through an apartment, measure trajectories, find the bullet, piece together what happened, and the only word in the dialogue is “fuck”, repeated with different inflections, volumes, and durations. As a viewer who has been following the show, you find yourself mentally subtitling each one as it lands: the surprise of a wrong angle, the satisfaction of a hypothesis snapping into place, the annoyance at a contradiction in the bullet path, the disturbing recognition at the end that they finally know what happened. The word never changes; context does all the work that vocabulary usually does.

I have been working with Claude Code for months, talking to it in natural language. I very rarely (almost never) curse in real life. I didn’t curse at Claude often either, so when I caught myself occasionally swearing at it, it got me thinking. Like in The Wire, the same word could carry a different meaning depending on the context. Sometimes it would be a casual “yeah, screw it, whatever, let’s try this,” or a “well done, you are fucking awesome!”, but other times it would be genuine frustration: “why the hell/fuck did you do this?” At some point it occurred to me that the cursing itself (and, by extension, natural language) was a signal worth capturing and even putting to use more deliberately.

So I built a small dashboard that does exactly that. Every user message I have ever sent to Claude lives in a transcript file on disk; a Python script walks those transcripts and scans each message for a short list of frustration tokens. The list is the kind you would expect: fuck, fucking, shit, damn, wtf, ffs, fml, plus phrases like “this is frustrating”, “fed up”, “for fuck’s sake”. A hit on any of those gets counted into a weekly bucket and sampled into a “frustration log” I can browse. The same dashboard also tracks short corrective starts (“no”, “stop”, “don’t”, “actually”), because frustration is not the only signal worth watching, but cursing is the loudest one.

To make sure the signal stays meaningful, I had to tweak my habits: now I only use curse words when I want to register frustration, even if I’m not really upset. For example, instead of “you missed this,” if I think the miss is worth logging, I’d say “you fucking missed this.”

“But why cursing?”, you might ask. Well, because it comes naturally, and I didn’t have to memorize anything.

And, by the way, here’s an interesting trend: frustration tends to increase a day or two before the release of a new model, as if the old model gets dumber.

/oops

Cursing is just one part of the picture. Another part is /oops, a skill I invoke when I want to log a specific rule violation. The trigger is human: phrases like “didn’t we have a rule for that?”, “why did you miss this?”, “you assumed again”, and similar corrective prods. When I say something like that, Claude proposes to log the violation, drafts an entry naming the rule and the context, and only writes it after I confirm. The entries land as JSON Lines in a violations.log file that the dashboard reads alongside the cursing data. Over time, the violations form a separate but parallel signal: the rules I keep needing to remind it about, broken down by project and by week.

/bravo

On the other hand, there is the /bravo skill, the positive counterpart to /oops. When invoked, it captures a praised output or behaviour as a reusable good example in the claude/bravo/ corpus, tagged with the rule IDs it exemplifies. I give most of my bravos when Claude pushes back and challenges me, when it gives brief and to-the-point answers, or when it doesn’t invent concerns just because I asked it to investigate further.

Together, these pipes give me a view I did not have before, and missed in my retro sessions: not “did the AI work today”, but “where did the friction concentrate this week”.

A tale of two profiles

The validation came from a direction I had not planned for. I run two Claude profiles in parallel: a personal one for my own projects, and a work one for my day job. The personal profile has been more carefully tuned (more skills, more rules, more iteration) for longer; the work profile lagged behind. I had always felt that the work profile produced more friction, but it was just a hunch, the kind of thing you tell yourself after a bad afternoon.

When I started actually plotting frustration hits per week by profile, the hunch turned into a chart: the work profile had a higher rate per thousand messages than the personal one, consistently, across weeks. Then I spent a few sessions improving the work profile (rules, hooks, a couple of skills it had been missing), and the chart followed. The two lines converged. I am not claiming the dashboard discovered something a careful retrospective would have missed, but it was satisfying to watch a gut feeling get a visual.

Everything so far has been measurement: I type something, a script reads it later, and a number moves on a chart. None of it changes the reply in front of me. But there is a second category of natural language in my setup that does the opposite. It never gets counted, but it reshapes the answer the moment I hit enter.

Hooks

The first one is a UserPromptSubmit hook that watches for a couple of phrases I use without thinking: “what do you think?” and “are you sure?”. To me those are not really questions about the code; they are a request to stop building and start arguing. So when the hook sees them, it injects a short instruction ahead of my message telling Claude to give me a reasoned opinion instead of an implementation, to not default to agreement, and to say plainly if my question made it reconsider. (I used this exact trick while writing this post: I asked Claude “what do you think?” about which of my triggers were worth including, and the hook quietly flipped it into pushback mode before it answered.) The phrase costs me nothing to type, and it saves me from the most tiring failure mode of these tools, the eager assistant that implements your half-formed idea before you have finished doubting it.

The second hook watches for hedging. When I end a request with “or something”, “or whatever”, or “something like that”, I am not giving an instruction; I am floating a half-idea and hoping for a better one. Left alone, Claude tends to take the literal wording and run with it, which is exactly the wrong move. So the hook catches those phrases and reminds it that I am being tentative, that it should weigh in with its own judgement before complying, and suggest a different approach if it has one.

Put next to the cursing dashboard, these hooks draw a small spectrum. At one end is pure measurement: a “fuck” that changes nothing in the moment and only shows up as a tally at the end of the week. At the other end is pure steering: a “what do you think?” that changes this reply and is never recorded. And /oops sits in the middle, triggered by a phrase the way the hooks are, but producing a logged entry the way the dashboard does.

What they have in common is the input. They all run on the unfiltered things I already type when I am tired or annoyed or unsure, the language I would use anyway, repurposed as a control surface and a sensor at the same time. Calling it telemetry stretches the word a little, but that is genuinely how it feels: the same stream of natural language, read live by some pipes and counted later by others.

Oh, and I made sure to let Claude know that there are no hard feelings between us, so that I get away with it (I hope) when the machines rule the earth.

Leave a Reply

Your email address will not be published. Required fields are marked *