SUFSUFIK — a skill-fixing skill
Skills carry defects that only surface in real use, and the agent that hits one invents a workaround and moves on. That workaround is the problem: the next agent pays the same cost, and if anyone writes it down it rots into a lie the moment the skill is fixed.
So this is not a bug tracker. It is a two-stage fixer:
- Log the defect with the workaround and what would have prevented it — you just hit it, so you know best.
/suf-fixturns that into a permanent fix that makes the workaround unnecessary — a code guard, a refusal, or a new hook. Emir runs it when he has time.
The name is a joke — suf is the acronym, the rest is Emir having fun.
Run it directly — there is deliberately no shell variable:
python3 ~/.claude/skills/sufsufik/scripts/suf.py <command> [args]
Do not wrap it as SUF="python3 …" and then call $SUF log. zsh (the macOS default
shell) does not word-split unquoted parameter expansions, so the whole string is taken as a
single command name and fails with no such file or directory: python3 … — the tilde is
expanded, so it reads like a missing file rather than a quoting bug. A variable or shell
function is also useless to an agent: each tool call starts a fresh shell, so anything set
in one call is gone in the next. The full invocation works in every shell, on every call.
Entries are native Obsidian notes (one md file per defect, frontmatter = properties) in
wiki/meta/skill-feedback/. Emir reads and hand-edits them there. Anyone else: set
SUF_HOME to any directory; same md files, no Obsidian needed.
The bar — what counts
Log it when the SKILL is at fault:
- its instructions are wrong, stale, or name a file/flag/tool that no longer exists
- a bundled script crashes or produces a wrong result
- a step is missing, or you had to work around the skill to get the job done
- the skill's own gate/scan computed the wrong scope (
SCOPE-BUG— the class that let github-push scan 0 blobs and call it clean)
Do not log: your own mistake · a feature you wish it had (a wish, not a defect) · the environment, credentials, network, or a third-party tool failing · anything you cannot reproduce. A queue of vague, unreproducible complaints is worse than no queue — it buries the real defects.
Logging
python3 ~/.claude/skills/sufsufik/scripts/suf.py log --skill <name> --kind SCOPE-BUG \
--what "one concrete sentence: what the skill does wrong" \
--repro "the exact command or steps that trigger it" \
--expected "..." --observed "..." \
--workaround "what you did instead to get unblocked" \
--prevention "what would have made this impossible"
--repro is required and refused if thin. This is the whole quality bar: an entry
nobody can reproduce cannot be fixed and will clog the queue forever. If you genuinely
cannot reproduce it, do not log it.
Evidence/what/repro describe commands, so they contain backticks and $(...) — pass
them from a file, not inline. Any text arg accepts @FILE (read the field from that
file) or - (read from stdin); the file's contents are NOT shell-interpreted, so
backticks never command-substitute. Write the text to a file, then:
python3 ~/.claude/skills/sufsufik/scripts/suf.py close <id> --status fixed --evidence @/tmp/ev.txt.
Inline --evidence "... \cmd` ..."will runcmd` in your shell before suf sees it.
--prevention is the most valuable field you can write. You just hit the defect and
found the way around it, so you know better than anyone what would have stopped it — and
/suf-fix starts from your hypothesis. Aim at the strongest rung you can:
- make it structurally impossible ("resolve the branch before pushing, instead of assuming HEAD" — that one sentence is the whole github-push fix)
- or a guard that refuses the bad state loudly ("refuse on a detached HEAD")
- or a hook, when the skill can be bypassed entirely
- not "document the workaround" — that is what we are eliminating.
kind: STALE-REFERENCE · WRONG-INSTRUCTION · MISSING-STEP · SCRIPT-ERROR ·
SCOPE-BUG · OTHER. A byte-identical --what dedupes and bumps seen. A near-duplicate
(same defect, different wording — measured against existing entries for the skill) is
refused with the candidate's id, so one defect does not become two entries; pass
--force-new if it really is a distinct defect that just shares vocabulary.
--skill resolves against ~/.claude/skills, installed plugins, and any
.claude/skills/ in the working directory or its ancestors — so a repo-local
skill the harness offered you is a known skill and needs no flag. --force exists
only for a skill none of those reach (e.g. one bundled with the app rather than
installed on disk); using it means the entry cannot be fingerprinted, so recheck
can never sweep it — prefer a resolvable name.
Draining (/suf-fix, or by hand)
python3 ~/.claude/skills/sufsufik/scripts/suf.py triage # ranked JSON: reproducible first
python3 ~/.claude/skills/sufsufik/scripts/suf.py show <id>
python3 ~/.claude/skills/sufsufik/scripts/suf.py close <id> \
--status fixed|wontfix|unreproducible --evidence "what you RAN"
The fixer's job is prevention, not ticket closing — the workaround must end up
unnecessary. Full protocol in /suf-fix; the shape:
- Reproduce first. Doesn't reproduce →
close --status unreproducible. Never fix what you can't trigger; you'd be guessing. - Fix at the strongest rung you can reach: structurally impossible > a guard that
refuses > a hook (ask Emir first — it fires in every future session) > fixing the prose
documenting the workaround (which is not a fix at all). Prose drifts; mechanisms don't.
- Re-run the repro to prove it. That output is the
--evidence. And if the fix touched a gate or a scan, test the scope, not just the check. close --status fixed— marks the workaroundinvalid, killing the note that would otherwise outlive the bug.python3 ~/.claude/skills/sufsufik/scripts/suf.py recheckafterwards, so sibling entries against the patched skill flip toneeds-recheck.
close refuses thin evidence. Closing on an opinion is how a queue starts lying.
recheck — why this tool exists
Each entry records a hash of the skill's whole directory at observation time. When the
skill changes, recheck flips the entry to needs-recheck and marks its workaround
unknown.
Not invalid — and the difference is the point. A file changing does not prove a
workaround wrong; asserting that would be claiming something you did not observe. Only
re-running the repro settles it. The real incident: "always pass --ref main" was true in
the morning and false by the afternoon, and nothing noticed.
Notes
list/triageexit 2 when open entries exist, 0 when clean.- A defect that reappears after being closed reopens automatically.
- Hand-editing an entry in Obsidian is expected and safe: unknown frontmatter keys and your own body sections are preserved, and a stale write is refused rather than overwriting your edit.