<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Denys Severyn</title>
    <description>The latest articles on DEV Community by Denys Severyn (@denys_severyn_1a538d691e6).</description>
    <link>https://dev.to/denys_severyn_1a538d691e6</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4196812%2F445b8cc7-65a0-4cf9-ad05-57066cb27084.png</url>
      <title>DEV Community: Denys Severyn</title>
      <link>https://dev.to/denys_severyn_1a538d691e6</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/denys_severyn_1a538d691e6"/>
    <language>en</language>
    <item>
      <title>Your reviewer remembers. Claude doesn't. A small plugin for the gap.</title>
      <dc:creator>Denys Severyn</dc:creator>
      <pubDate>Tue, 20 Oct 2026 19:53:26 +0000</pubDate>
      <link>https://dev.to/denys_severyn_1a538d691e6/19-review-comments-one-mistake-zero-memory-giving-claude-code-a-guilty-conscience-5bkf</link>
      <guid>https://dev.to/denys_severyn_1a538d691e6/19-review-comments-one-mistake-zero-memory-giving-claude-code-a-guilty-conscience-5bkf</guid>
      <description>&lt;p&gt;Claude Code writes code that works. It builds, the tests pass, CI is green. Then a human on the team opens the PR.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A type that's fine inside the app but can't be sent to another service. It compiles, it gets sent, the other side can't read it. The network doesn't care how elegant your types are.&lt;/li&gt;
&lt;li&gt;A variable called &lt;code&gt;result&lt;/code&gt;. In a codebase where even the loop counters have proper names.&lt;/li&gt;
&lt;li&gt;The handler got changed. The validation sitting right next to it didn't. The test still passed because it never looked at the new field.&lt;/li&gt;
&lt;li&gt;The old name, still sitting in a list two folders away from everything Claude touched.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that was written down anywhere. All of it was known to every person on the team, including the one who started last week. That's the gap: the stuff people know and never wrote down. The reviewer has it. Claude doesn't. And the only thing moving it across is the reviewer, typing the same comment again, a little shorter each time.&lt;/p&gt;

&lt;p&gt;Each comment gets fixed. Next PR, same mistake, different file. Fixing the comment fixes today. Writing down &lt;em&gt;why it happened&lt;/em&gt; is the only thing that fixes next week.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I tried first
&lt;/h2&gt;

&lt;p&gt;A file called &lt;code&gt;lessons.md&lt;/code&gt;, pulled into &lt;code&gt;CLAUDE.md&lt;/code&gt;. One rule for Claude: when a reviewer catches something, add a line.&lt;/p&gt;

&lt;p&gt;Three months later: 99 lines, 312 additions logged, and the top line had been caught by reviewers 19 times. Not 19 reviewers. One mistake, "after a rename, search the whole repo, not just the files you touched", caught 19 times, each with a new twist, by people with steadily less patience. Second place was at 10. Third at 8. The file had quietly turned into a leaderboard.&lt;/p&gt;

&lt;p&gt;And Claude had every line of it, in front of it, every single session. Didn't matter. An hour into a change, that line is buried behind three file reads and a test run. The problem was never memory. It was timing. Nobody re-reads the safety card halfway through the flight.&lt;/p&gt;

&lt;p&gt;Next attempt: four small shell scripts that Claude Code runs at certain moments, leaning on a tool called &lt;code&gt;jq&lt;/code&gt;. Every script started with "if &lt;code&gt;jq&lt;/code&gt; isn't installed, quietly exit". On a machine without &lt;code&gt;jq&lt;/code&gt;, the whole thing was dead. No error, no message, nothing. I found out weeks later. It had achieved perfect silence, which is the one thing it existed to prevent.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, tacit
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/N1XUS/tacit" rel="noopener noreferrer"&gt;github.com/N1XUS/tacit&lt;/a&gt;. A Claude Code plugin. The things it keeps are called &lt;em&gt;papercuts&lt;/em&gt;: small, they repeat, they add up. It does three things.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ask why, not what
&lt;/h3&gt;

&lt;p&gt;When Claude pulls down the review comments on a PR, the plugin steps in and says: fix them, and for each one you fix, answer one question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why did I write it that way? What kind of mistake is this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"I forgot to remove the old name" isn't an answer. "I only looked at the files I was already editing" is. The first one gets you a sticky note. The second one gets you a habit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two lists, on purpose
&lt;/h3&gt;

&lt;p&gt;One list for the general rule, one for how it shows up in this particular repo.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Everywhere, &lt;code&gt;~/.claude/papercuts.md&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;"Anything sent to another service uses plain, concrete types. Never interfaces."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;This repo, &lt;code&gt;.claude/papercuts.md&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;"Message types live in this folder. Check it for interface-typed fields before you push."&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I fought this for a while. One file felt cleaner. But "every line must be general" and "after the second time, rewrite it as an exact command" can't both live in one file, because exact commands depend on your stack. Two files. Took me embarrassingly long to accept that.&lt;/p&gt;

&lt;p&gt;You can also tie a list to certain files, so your SQL rules only show up when Claude is writing SQL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Show up at the right moment
&lt;/h3&gt;

&lt;p&gt;This is the part that actually changed things. The list gets put in front of Claude:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;when a session starts, and again after Claude's memory gets squeezed down mid-session,&lt;/li&gt;
&lt;li&gt;on the first file edit, then every 15th,&lt;/li&gt;
&lt;li&gt;right before &lt;code&gt;git push&lt;/code&gt; or opening a PR,&lt;/li&gt;
&lt;li&gt;right after it pulls review comments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not on every edit. Text that shows up two hundred times a session becomes wallpaper, and Claude learns to skip it about as fast as you learned to skip cookie banners.&lt;/p&gt;

&lt;p&gt;Every trigger is something that actually happened: a command ran, a file is about to be written. It never guesses what you meant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping score, honestly
&lt;/h2&gt;

&lt;p&gt;Every line in the general list ends with a count: how many times a reviewer has caught it. Same mistake again? Bump the count and sharpen the wording. Don't add a near-duplicate. Once a line hits 2, a check fails and tells you: the wording isn't working, turn it into a concrete step.&lt;/p&gt;

&lt;p&gt;The catch: Claude reports its own count. Asking a model to tally its own mistakes is asking a cat to log its own vase incidents. The easy way out of "don't duplicate, increment" is to duplicate anyway and report a clean conscience. So every addition also writes one line to a separate log, and &lt;code&gt;tacit audit&lt;/code&gt; compares the two. If the log has more entries than the counts add up to, something got added quietly. That's not a feeling, it's a number.&lt;/p&gt;

&lt;p&gt;Hard limit: 30 lines per list. Line 31 is where checklists go to become decoration. A list nobody reads is worse than no list, because it looks like you're covered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two rules I won't break
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The plugin never touches permissions. Technically it could approve a &lt;code&gt;git push&lt;/code&gt; on your behalf without asking you. Mine never does, and there's a test that makes sure.&lt;/li&gt;
&lt;li&gt;The plugin never breaks what Claude was doing. If anything goes wrong, it goes quiet. And because "going quiet" is exactly what bit me with the shell scripts, there's a &lt;code&gt;tacit doctor&lt;/code&gt; command whose only job is to tell you whether it's actually running.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The part I built and deleted the same day
&lt;/h2&gt;

&lt;p&gt;Catching corrections in chat. "No, we don't do it like that, here's how." There's no fixed shape to that sentence. I tried three ways.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pattern matching.&lt;/strong&gt; Careful, safe, bounded. Only works in English. Fine as a fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asking a small model.&lt;/strong&gt; One cheap call to Haiku per message, four tokens back, yes or no. About a hundredth of a cent. Worked great in tests. Then I asked the obvious question: does it work if you're on a Claude subscription instead of paying per call? No. Subscription sessions don't have an API key lying around for the plugin to use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starting a second Claude in the background.&lt;/strong&gt; Uses the session's own login, so subscriptions work. Also: almost four seconds to boot, a whole extra session eating into your limits, all to say "yes". Hiring a consultant to nod.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then the obvious thing. The smartest model in the room is the one already reading the message. So the plugin just drops in one line, on the first message and every tenth after: &lt;em&gt;if the user is asking for a review, fixing PR comments, or telling you something's wrong, here's what to do.&lt;/em&gt; Claude decides. Works in any language. Costs about sixty tokens per ten messages. A full day of clever to arrive at the dumb option.&lt;/p&gt;

&lt;p&gt;All three of the clever ones are gone from the code. Not behind a setting. Gone. Dead code behind an opt-in is just dead code with a nicer funeral.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doesn't Claude Code do this already?
&lt;/h2&gt;

&lt;p&gt;I checked, same day, against the current docs. Claude Code now has its own memory, and it does record your corrections. &lt;code&gt;CLAUDE.md&lt;/code&gt; survives when the session gets squeezed down, which it didn't used to. Both good.&lt;/p&gt;

&lt;p&gt;But nothing built in asks &lt;em&gt;why&lt;/em&gt; a review comment happened. Nothing counts how often the same one comes back, or checks that count against reality. Nothing separates "true everywhere" from "true in this repo". And nothing puts a checklist in front of Claude at the moment it's about to write or push. That's the whole reason this exists. The day those ship natively, I delete it, gladly. I have other papercuts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude plugin marketplace add N1XUS/tacit
claude plugin &lt;span class="nb"&gt;install &lt;/span&gt;tacit@tacit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then fetch the comments on any PR and watch it ask for the why.&lt;/p&gt;

&lt;p&gt;Your lists are plain markdown files in your home folder and your repo. Disable the plugin and they're still there. Like real papercuts.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
