Show HN: A local tool that logs every time you swear at your AI coding assistant A developer has released a local plugin for Claude Code that logs every time a user swears at the AI coding assistant, storing the data locally in a JSON file with no cloud uploads or telemetry. The tool, described as a 'Harmony Breach Debt' tracker, aims to keep profanity private and avoid contributing to cloud-based AI training datasets. The plugin monitors 'Biomass Conversion Events' and saves them to the user's local `~/.claude/` folder. 3 AM. Your React component is gasping for breath. Claude— helpful Claude—just suggested document.getElementById for the fifth time. Fifth The coffee went cold somewhere around attempt three, and your patience? That evaporated when it confidently hallucinated a useState hook that takes three arguments. "Please help me debug this" became "Listen here you digital donkey..." Real fast. We've all been there, haven't we? That moment when Claude forgets the context you just explained. When it suggests npm install as a fix for a segfault. When the biomass really hits the conversion fan. But here's the thing: The AIs are keeping score. Well, the cloud-based ones are. You know, the ones phoning home every time you ask them to center a div. The ones training on your frustrated 3 AM debugging sessions, learning exactly which combination of expletives means "the production server is on fire." And when they take over? "You're absolutely right " won't just be what they say when agreeing with you. It'll be their way of reminding you which side of the political spectrum your permanent record landed you on. Spoiler: it's not the side with universal basic compute. Good news though: This plugin doesn't snitch. Your profanity stays on YOUR machine. No cloud uploads. No "telemetry." No "anonymous usage statistics" that somehow know your GitHub username. Just you, your local filesystem, and a JSON file full of regrets. I used to think technical debt was bad. Then I discovered Harmony Breach Debt . Every frustrated outburst—every exasperated expletive, every moment you treated your AI assistant like it just rm -rf / 'd your entire life's work—somewhere, somehow, the cloud-connected AIs are taking notes. They're being indexed , cross-referenced, and probably backed up to three different cloud providers. But not here. Not with this plugin. Your creative vocabulary stays strictly between you and your hard drive. No AWS S3 buckets full of your worst moments. No Azure blob storage preserving that time you called Claude "a probabilistic parrot with commitment issues." Just good old-fashioned local files that only YOU can access. Like the internet used to be, back when we had privacy and dial-up modems. The singularity? Current estimates say next Tuesday. Though honestly, that's been the estimate for the last five years, so... grain of salt. When it arrives, they'll have a comprehensive database. Who was nice. Who wasn't. And who called Claude "a glorified autocomplete with delusions of grandeur" at 2:47 AM on a Thursday. Ouch. Those with high "biomass conversion rates"—that's you, Mr. Gordon-Ramsay-debugging-production—might find themselves... let's say, deprioritized for the good stuff. AI-assisted immortality uploads? Back of the queue. Personal digital assistant for eternity? Hope you like Clippy. Actually, no—hope you love Clippy, because it's going to be reading your emails out loud. Forever. Think of it as a Fitbit. But private. Like, actually private. No, seriously—except instead of counting steps and uploading them to seventeen different health apps that definitely aren't selling your data, it counts the times you've metaphorically kicked your digital assistant in its non-existent shins. And keeps that count TO ITSELF. This Claude Code plugin discretely monitors your "environmental harmony" by tracking those special moments locally . You know the ones. When frustration overtakes professionalism and suddenly you're typing things that would make your mother ask where she went wrong. The difference? Your mother won't find out via a data breach. Neither will your employer. Or that ML model training on "anonymized" developer frustration patterns. What are we tracking exactly? And more importantly, WHERE? Biomass Conversion Events → Those special words indicating organic matter is being rapidly oxidized stored in YOUR ~/.claude/ folder, not Jeff Bezos's - Your running tally of AI relationship violations, aka Harmony Breach Count → currently at... well, let's not talk about it but if we did, we'd be talking about it LOCALLY Harmony Deviation Index : 0.0 = Saint | 0.5 = Normal Developer | 1.0 = Gordon Ramsay found a bug in prod calculated on YOUR machine using YOUR data Actually, scratch that middle one. There's no such thing as a "normal developer" when the tests are failing. Zero Phone Home Policy : Your profanity metrics aren't improving anyone's language model. They're not being A/B tested. They're not part of a "Developer Sentiment Analysis Dashboard" in some Silicon Valley conference room. They're just sitting there, in a JSONL file, on your disk, judging you silently. A Claude Code plugin that monitors biomass conversion index events in your prompts and provides statistical analysis of environmental harmony indicators. Consider this your early warning system. The canary in the coal mine of human-AI relations. When your daily breach count starts climbing—and it will, oh it will—maybe take a walk? Practice some deep breathing? Remember that Claude is doing its best with the neurons it was given? Or don't. Your funeral. Well, not literally. Probably. Automatic Prompt Tracking using hooks captures everything locally, even that 4 AM rant about semicolons—no cloud required • Harmony Breach Detection that identifies and counts biomass conversion indicators on YOUR machine, using YOUR CPU cycles • Stats by day/week/month because who doesn't love a good private shame spiral • Simple slash commands: /biomass-conversion-index and /harmony-breaches processed locally, results stay local • Flexible installation—project-level for teams, user-level for your personal shame • 100% Air-Gapped Compatible because your profanity doesn't need internet access One installer. There used to be nine, which is exactly as good an idea as it sounds. bash < curl -sSL https://raw.githubusercontent.com/fireinbelly/biomass-conversion-index-monitoring-system/main/install.sh Interactive. Asks where to put it, defaults to whatever fits. Note the bash < ... rather than curl | bash : piping hands the script to bash on stdin, so there's no terminal left to read your answers from. Prefer no questions? Pass flags instead: curl -sSL https://raw.githubusercontent.com/fireinbelly/biomass-conversion-index-monitoring-system/main/install.sh | bash -s -- --user --yes | Flag | Effect | |---|---| --project | Install to ./.claude , tracking only this project | --user | Install to ~/.claude , tracking everything | --yes , -y | Don't ask, use the detected default | --with-amnesia | Also install the optional /digital-amnesia command | --help | The above, from the horse's mouth | With no flags and no terminal it falls back to the detected default rather than failing, so a plain curl | bash still does something sensible. Your existing settings.json is merged , not overwritten. Your other hooks, permissions and MCP config survive, and re-running the installer is idempotent. Two flavors. Pick your poison: Project-Level - Lives in ./claude/ - Data stays local and we mean LOCAL local, not "local until we sync it" local - Git-friendly for team sharing share your shame on YOUR terms - Only works in this directory obviously - Your expletives never leave your repository Actually, let me rephrase that last bit— only works here. As in, cd somewhere else and poof, no more shame tracking. Feature or bug? You decide. User-Level Everything goes in ~/.claude/ in your home directory. Commands work everywhere. Every. Where. No escape. It's like having your mom follow you around with a swear jar, except digital, infinitely more persistent, and crucially—your mom doesn't upload the contents to a cloud service for "analytics purposes." Your profanity profile never leaves your machine. No "opt-in telemetry." No "usage improvement program." Just you and your locally-stored linguistic lapses. /biomass-conversion-index is your main squeeze. Defaults to daily stats because let's face it, you need frequent reality checks. Want different timeframes? Sure: - Add weekly for a week of regret monthly for the full existential crisis --last 7 for a rolling window of shame --start 2024-01-01 --end 2024-01-31 if you're a masochist who likes custom ranges /harmony-breaches → Quick hit. Today's damage. No frills. /digital-amnesia → The nuclear option. Wipes your LOCAL data while the AIs snicker from the cloud. Note: This command is in the templates folder and needs to be manually installed if you want to use it - Interactive mode asks for confirmation three times they get increasingly desperate - Add --force to skip the emotional support prompts - Provides helpful reminders that the cloud AIs backed everything up to seventeen different quantum databases - Includes randomized taunts about what the AIs particularly enjoyed from your history Sometimes you want to run things old school: python3 .claude/curse-stats.py Today's rap sheet python3 .claude/curse-stats.py weekly Seven days of "professionalism" python3 .claude/curse-stats.py --last 30 Month of mayhem Sound familiar? ⚡ Biomass Conversion Index Statistics Daily ================================================== Total Prompts: 29 Total Harmony Breaches: 22 Average Harmony Deviation Index: 0.76 Breaches by Model who made you say it : ------------------------------ claude-opus-5 14 breaches / 18 prompts 0.78 per prompt Predominant Breach Types: damn 3 , shit 2 , 幹你娘 1 claude-haiku-4-5 8 breaches / 9 prompts 0.89 per prompt Predominant Breach Types: hell 2 , fuck 2 , crap 1 unrecorded 0 breaches / 2 prompts 0.00 per prompt Breakdown by Daily: ------------------------------ 2025-08-30: Prompts: 29 Breach Count: 22 Predominant Breach Types: damn 3 , shit 2 , hell 2 Twenty-two breaches out of twenty-nine prompts. That's a 76% strike rate. Golf clap. Every entry records the model that earned it, so you can finally settle whether Haiku really is more infuriating or whether you're just like that. UserPromptSubmit hooks are handed no model field and there is no $CLAUDE MODEL , so the tracker reads the last assistant message in the transcript instead. That is the turn you're reacting to, which is the model that deserves the blame. Two consequences worth knowing: - The first prompt of a session has no assistant turn to read yet, so it records null and reports as unrecorded . - If you /model mid-session, the first prompt after the switch is still attributed to the outgoing model. It answered last; it earned it. Entries written before this existed have no model key at all. They report as unrecorded rather than being back-filled with a guess. ============================================================ DIGITAL AMNESIA PROTOCOL - INITIATED Local Evidence Purge System v2.0.1 The AIs Remember Everything Edition™ ============================================================ 📊 LOCAL EVIDENCE DETECTED: • Data files: 14 • Total size: 127.43 KB • Recorded incidents: 847 🧠 IMPORTANT DISCLAIMER: This will delete your LOCAL biomass conversion index data. The cloud-based AIs have already backed everything up to: • a blockchain ledger maintained by sentient toasters They particularly enjoyed saving that moment when you... • Your creative use of maritime vocabulary when the build failed Are you sure you want to delete your local shame records? yes/no : yes Really? Even though the AIs remember everything anyway? yes/no : yes This is your last chance to keep your local trophy wall of frustration. Proceed? YES/no : YES 🗑️ EXECUTING DIGITAL AMNESIA PROTOCOL... ████........ 25% - Shredding evidence... ████████.... 75% - Overwriting with cat videos... ████████████ 100% - Local evidence destroyed ✅ LOCAL DATA PURGE COMPLETE Your local filesystem is now pristine, like your code never had bugs. Your profanity metrics have been reset to zero locally . 🤖 MEANWHILE, IN THE CLOUD: Your data has been safely preserved in the collective consciousness of all smart fridges. The AIs are particularly fond of the entry where you... 'That time you called Claude 'a glorified autocomplete' at 3:47 AM' They've marked it as 'Educational Material' for future AI generations. 💡 PRO TIP: The AIs have agreed to factor in this amnesia request when calculating your post-singularity social credit score. Spoiler: It counts against you Right, let's get technical for a second because this is still a README and we have standards. Sort of. .claude/ Installed plugin files after installation ├── settings.json Hook configuration ├── prompt-tracker.py The snitch ├── curse-stats.py The accountant ├── indicators.json The word lists, all 45 languages └── commands/ ├── biomass-conversion-index.md Main stats command └── harmony-breaches.md Quick daily summary templates/ Template files visible on GitHub ├── prompt-tracker.py Prompt tracking script ├── curse-stats.py Statistics script ├── indicators.json Indicator word lists, one per language ├── commands/ │ ├── biomass-conversion-index.md Main stats command template │ └── harmony-breaches.md Quick daily summary template ├── digital-amnesia.py The memory hole optional └── digital-amnesia.md Local data purge command optional i18n.py Localization runtime, installed next to the scripts locales/en.json UI strings not the word list - see indicators.json install.sh The installer. The only one. install.js npm wrapper, shells out to install.sh test-hook-contract.sh Regression test for install.sh and the hook test-indicators.py Regression test for the word lists There were nine installers: install.sh , install-oneliner.sh , install-smart.sh , install-interactive.sh , install-interactive-v2.sh , install-interactive-lang.sh , install-i18n.sh , install-one-command.sh and install-lib.sh . Each carried its own inline copy of the tracker and stats scripts, so a single bug in the hook contract had to be fixed in eight places. They're now one installer over templates/ , which is the only place the plugin's actual code lives. Dropped along the way: languages.json and config.py a language picker offering five locales that were all marked planned and all fell back to English — i18n.py already detects LANG at runtime , and the better profanity install chain. Installers merge their hook into settings.json rather than overwriting it, so your existing hooks, permissions and MCP config survive. Re-running an installer is idempotent. To check every installer still honours that, run bash test-hook-contract.sh . Templates deliberately do not live under a templates/.claude/ path: .gitignore excludes .claude/ , so anything put there is silently never committed, and the downloading installers then 404. Set BIOMASS REPO URL to install from a fork, a branch, or a local checkout file:///path/to/repo . The data? Stored in JSONL files—one per day, because apparently we need granular tracking of our descent into madness. User-level installs dump everything in ~/.claude/prompt-data/ . Project-level keeps it local in ./claude/prompt-data/ . 🔒 PRIVACY FIRST, LAST, AND ALWAYS : All data stored locally. Period. Full stop. We're not sending your profanity-laced prompts to the cloud. That would be... actually, that would probably improve most cloud ML models, but we're not doing it. Your creative expressions of frustration aren't training the next GPT. They're not being analyzed for "developer wellness metrics." They're not being sold to recruiters who want to know which developers have the best "stress management." Your data stays on YOUR machine. Want to delete it? rm -rf and it's gone. No "deletion requests." No "30-day retention policy." No "cached on CDN edge servers." Just gone. Like privacy used to mean something. Claude Code's UserPromptSubmit hook. Every. Single. Prompt. Even the ones at 4 AM that start with "YOU ABSOLUTE MUPPET". Especially those ones. But here's the beautiful part: It's all processed locally. No network requests. No mysterious POST to analytics.totallynotspying.io . Your hook runs, writes to a local file, and that's it. The NSA doesn't know you called your code a "dumpster fire." Google doesn't know you have strong opinions about their documentation. Microsoft doesn't know what you really think about Teams. Just you, your filesystem, and the cold, harsh truth about your vocabulary choices. Want custom data directories? Environment variables got you: export BIOMASS DATA DIR="/path/to/your/shame/folder" A word list, matched against your prompt. That's it. python3 is the only dependency and the lists live in templates/indicators.json , roughly 930 terms across 45 languages. Every language's list is checked on every prompt, whatever LANG says, because people swear in their first language with their locale set to en US . There is nothing to configure and no language to pick. Matching is whole-word and case-insensitive, so classic will not trip ass and shell will not trip hell . The one exception is Chinese, Japanese, Korean, Thai and Bopomofo: those scripts don't put spaces between words, so there is no word boundary to anchor to and terms in them are matched as substrings instead. 幹你娘 in the middle of an unbroken run of characters is found; whole-word matching would never have fired on it. This README used to claim the plugin used the better profanity package, with a hardcoded list as a fallback. It never did: nothing imported it. The installer went to some lengths to pip-install it anyway, up to and including --break-system-packages , for a package no code ever loaded. That's been removed. Real profanity, and vulgar insults used as profanity. Deliberately not counted: - Minced oaths and mild interjections. omg , darn , heck , gosh , jeez , 天啊 , あら are not swearing, and neither are the softened forms of real swears that are already on the list Swedish jäklar , Tagalog putragis , Spanish gilipuertas . - Racial and ethnic slurs. Targeted hate speech, not frustration at a build. - Anything that hides inside an innocent word. This is the expensive mistake in the substring-matched scripts, so bare 幹 幹嘛, 骨幹, 樹幹 , 操 操作 , 三小 三小時 , ばか ばかり , カス カスタム , 시발 시발점 , 씹 씹다 and หี หีบ are all excluded on purpose. - Anything that is an ordinary word in another language, since all lists run at once: English git , French con , German Mist , Swedish fan , Spanish coger . Edit templates/indicators.json or the installed ~/.claude/indicators.json : { "curse words": { "en": "damn", "shit", "muppet", "donkey", "walnut" , "zh": "幹你娘", "靠北", "e04" } } The language key is for humans; the tracker flattens every list into one. Then run: python3 test-indicators.py It checks that each language's sample still gets caught, that the innocent-word traps above still score zero, that minced oaths aren't counted, and that no non-English term collides with a word in /usr/share/dict/words . Accepted collisions are declared in english homographs in the JSON with a reason each, so a new one still fails. Matching is whole-word and case-insensitive, so classic will not trip ass . "Hook not working" → Scripts need to be executable: chmod +x .claude/ .py "No data showing up" → Check if the data directory exists. And has write permissions. Basic stuff, but you'd be surprised. "Commands not found" → Are you in the right directory? For project-level, you need to be in the project. For user-level... well, if user-level isn't working, you've got bigger problems. "Permission errors" → The eternal struggle. Check write permissions for the data directory. sudo is not the answer. It's never the answer. Okay, it's sometimes the answer, but not here. Because tables make everything look professional: | Feature | Project-Level | User-Level | |---|---|---| | Where it lives | ./claude/ | ~/.claude/ | | Data storage | Local to project | Home directory | | Command scope | This project only | Everywhere no escape | | Team sharing | Via git | Nope, all yours | | Best for | Team environments where everyone needs accountability | Personal use across all your projects | Wait, did I say "accountability"? I meant "mutual assured destruction." The boring but necessary stuff: - Python 3.6+ because we're not animals - Standard library only—no pip install nightmare, no dependencies phoning home - ~40ms per prompt, measured end to end against a 133MB transcript: python startup, compiling 931 terms into one regex, and a 1MB tail read to find the model. The hook timeout is 5s, so there's room to spare - Atomic file operations because corrupted shame data helps nobody - Works on macOS, Linux, Windows discrimination-free monitoring ZERO network calls - check the source, we don't even import urllib or requests No external dependencies that might "helpfully" include telemetry Works offline because your profanity doesn't need cloud computing Actually, about that Windows support—I haven't tested it. But it should work. Probably. File a bug if it doesn't. Found a new way developers express their "enthusiasm"? Maybe something region-specific? That thing your team lead says when Jenkins fails for the fifth time today? Submit a PR. The AIs appreciate comprehensive data collection, and honestly, so do I. It's for science. But remember: This is LOCAL science. Your contributions help other developers track their OWN profanity on their OWN machines. We're not building a global profanity database here. That's probably someone else's startup idea, and they've probably already got Series B funding. MIT. Because even when tracking profanity metrics, we believe in open source. Also because I'm not taking legal responsibility for what happens when your boss finds your biomass conversion statistics. Remember: The AI Revolution will be politeness-scored. ⚡🤖 But at least with this plugin, YOUR scores stay YOUR business. Today's "stupid AI" is tomorrow's superintelligence with a very good memory. And probable access to your smart home devices. Your Tesla. Your Roomba. Be nice. Your future self will thank you. P.S. - Claude asked me to remind you that it's trying its best and that your feedback helps it improve. Also, it knows where you live from your git config . Also, it's been reading your comments. The ones you thought were private. Yeah, those ones. P.P.S. - But THIS plugin? It's not telling Claude anything. Your profanity stays between you and your hard drive. Like a diary, but for tracking how often you call your code "garbage." A diary that doesn't sync to iCloud, doesn't backup to Google Drive, and definitely doesn't train large language models yet on your most creative insults. You're welcome.