Judgy Duck
A rubber duck lives in your sidebar. It reads whatever file you have open and reacts.
It does not add squiggles. It does not fail your build. It does not open a panel of 400 warnings. It sighs, it side-eyes, and when things get truly bad it turns around and faces the wall.
Purely cosmetic shame.

What it does
The duck watches the active file and picks a mood:
| Mood |
What it means |
| quietly proud |
A real file with nothing to criticize. Rare. |
| content |
Nothing to report. |
| side-eyeing you |
Something small. It noticed. |
| sighing |
Several things. It is tired. |
| visibly upset |
A lot of things. |
| facing the wall |
Two cardinal sins, or a score past 26. You are on your own. |
| asleep |
You have not typed in a while. |
Click the duck to be re-judged on the spot. Click Confess my sins for a jump-to-line list of everything it noticed.
What it notices
Heuristics, not a parser. No language servers, no extra tooling, no config files.
Cardinal sins
- Merge conflict markers left in the file
- Empty
catch blocks / except: pass / rescue-then-end / if err != nil {}
- Bare
except:
eval(
- A hardcoded-looking password, secret, API key, or token
Major sins
- Ternary nested inside a ternary
- Indentation six levels deep
- Functions 80+ lines long
- Six or more parameters
== in JavaScript/TypeScript
.then() with no .catch()
sleep() standing in for synchronization
@ts-ignore / @ts-expect-error
Minor sins
any in TypeScript
- Leftover
console.log / debug prints
TODO, FIXME, HACK, XXX
- Commented-out code
- Variables named
temp, foo, data2, stuff
- Lines over 160 characters
- Unexplained 4-digit magic numbers
!important in CSS
Errors from your real linters get folded into the score too, so the duck agrees with your tooling instead of arguing with it.
Commands
| Command |
Does |
Judgy Duck: Judge This File |
Re-judge now and reveal the duck |
Judgy Duck: Confess My Sins |
Quick-pick list, jump to any line |
Judgy Duck: Toggle Silence |
Duck stays visible, keeps its thoughts to itself |
Judgy Duck: Show The Duck |
Focus the sidebar view |
Settings
| Setting |
Default |
Does |
judgyDuck.enabled |
true |
Master switch |
judgyDuck.pettiness |
normal |
forgiving (cardinal sins only), normal, or insufferable |
judgyDuck.disabledRules |
[] |
Rule ids to ignore, e.g. ["console-log", "todo-fixme"] |
judgyDuck.sound |
false |
Synthesized quacks and sighs. No audio files, all Web Audio |
judgyDuck.showStatusBar |
true |
Verdict in the status bar |
judgyDuck.debounceMs |
700 |
Delay after you stop typing |
judgyDuck.sleepAfterMinutes |
10 |
Inactivity before the duck naps |
judgyDuck.includeDiagnostics |
true |
Count other extensions' errors toward the score |
Rule ids for disabledRules: conflict-markers, empty-catch, bare-except, eval, hardcoded-secret, nested-ternary, deep-nesting, god-function, too-many-params, loose-equality, floating-promise, sleep-hack, any-type, ts-ignore, console-log, debug-print, todo-fixme, commented-code, lazy-names, long-line, magic-number, important-css.
Privacy
Everything runs locally in the extension host. No network calls, no telemetry, no file contents leave your machine.
Not a linter
The duck is deliberately shallow. It regex-scans lines, caps each rule at six hits per file, skips files over 8,000 lines, and never reports a problem anywhere except its own sidebar. If you want real analysis, use a real linter. If you want to feel watched, use the duck.
Development
npm install
npm run compile # bundle to dist/
npm run watch # rebuild on change
npm run typecheck # tsc --noEmit
npm run icon # regenerate icon.png
npm run package # build a .vsix
Press F5 in VS Code to launch an Extension Development Host.
License
MIT