

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
1# Unslop — Maintainer Guide23This file is for agents and maintainers working on the unslop plugin itself. End-user docs live in [`README.md`](./README.md).45## README is a product artifact67The README is the product front door. Non-technical people read it to decide whether unslop is worth installing. Treat it like UI copy, not internal docs.89**Rules for any README change:**1011- Readable by non-AI-agent users. If you write "SessionStart hook injects system context", that phrase is invisible to most readers — translate it ("loads the unslop rules every time you open Claude Code").12- Keep the **Before / After** examples first. That is the pitch. Cutting them or burying them under prose breaks the conversion path.13- Install table must stay accurate. One broken install command costs a real user. Re-test every command in the install table on every PR that touches install scripts, plugin manifests, or hook paths.14- The "What unslop does" feature list must sync with the actual code. If a rule ships or gets removed in `unslop/scripts/humanize.py`, update the README in the same PR.15- Preserve voice. The README's terse, no-AI-ism style is intentional — it is unslop eating its own dog food. If you find a stock phrase ("comprehensive solution", "leverages cutting-edge"), a sycophancy opener ("Great question!"), or a hedging stack ("It's important to note that"), fix it in the same commit.16- Benchmark numbers come from real runs in `benchmarks/` and `evals/`. Never invent or round. Re-run the suite if you doubt a number you're about to print.17- Adding a new IDE/agent integration to the install table: also add a per-agent detail block in the appropriate `<details>` section so the table itself stays scannable.18- Readability check before any README commit: would a non-programmer understand the value prop and complete the install within 60 seconds? If not, simplify or move detail into `GETTING_STARTED.md`.1920## What this repo is2122A multi-platform plugin that makes assistant output sound human. Single source of truth (SSOT) files are synced to mirrored locations (Cursor, Windsurf, Codex bundle, etc.) by `scripts/sync-mirrors.sh` on push via `.github/workflows/sync.yml`.2324## Source of Truth2526Three files are authoritative. Every other location with the same name is a mirror, generated by `scripts/sync-mirrors.sh` (run by `.github/workflows/sync.yml`). **Edit the SSOT only.**2728| Concern | SSOT |29|---------|------|30| Main unslop skill | `skills/unslop/SKILL.md` |31| Always-on activation rule | `rules/unslop-activate.md` |32| File-rewriter skill | `unslop/SKILL.md` |3334Sub-skills (`unslop-commit`, `unslop-review`, `unslop-help`) are also authoritative under `skills/<name>/SKILL.md`.3536## Mirrored locations (do NOT edit by hand)3738- `unslop/SKILL.md` (top-level)39- `plugins/unslop/skills/unslop/SKILL.md`40- `.cursor/skills/unslop/SKILL.md`41- `.windsurf/skills/unslop/SKILL.md`42- `.cursor/rules/unslop.mdc`43- `.windsurf/rules/unslop.md`44- `.clinerules/unslop.md`45- `.github/copilot-instructions.md`46- `skills/unslop-file/SKILL.md`47- `skills/unslop-file/scripts/**`48- `plugins/unslop/skills/unslop-file/SKILL.md`49- `plugins/unslop/skills/unslop-file/scripts/**`5051The sync workflow handles all of these. If you edit a mirror, the next sync silently overwrites your change.5253## Hooks5455Four hook files live in `hooks/` plus a `unslop-config.js` shared module and a `package.json` CommonJS marker. Communicate via flag file at `$CLAUDE_CONFIG_DIR/.unslop-active` (falls back to `~/.claude/.unslop-active`).5657```58SessionStart hook ──writes mode──▶ $CLAUDE_CONFIG_DIR/.unslop-active ◀──writes mode── UserPromptSubmit hook59 │60 reads61 ▼62 unslop-statusline.sh63 [unslop] / [unslop:FULL] / ...64```6566`hooks/package.json` pins the directory to `{"type": "commonjs"}` so the `.js` hooks resolve as CJS even when an ancestor `package.json` (e.g. `~/.claude/package.json` from another plugin) declares `"type": "module"`. Without this, `require()` blows up with `ReferenceError: require is not defined in ES module scope`.6768All hooks honor `CLAUDE_CONFIG_DIR` for non-default Claude Code config locations.6970### `hooks/unslop-config.js` — shared module7172Exports:73- `getDefaultMode()` — resolves default mode from `UNSLOP_DEFAULT_MODE` env var, then `$XDG_CONFIG_HOME/unslop/config.json` / `~/.config/unslop/config.json` / `%APPDATA%\unslop\config.json`, then `'balanced'`74- `safeWriteFlag(flagPath, content)` — symlink-safe flag write. Refuses if flag target or its immediate parent is a symlink. Opens with `O_NOFOLLOW` where supported. Atomic temp + rename. Creates with `0600`. Protects against local attackers replacing the predictable flag path with a symlink to clobber files writable by the user. Used by both write hooks. Silent-fails on all filesystem errors.75- `readFlag(flagPath)` — symlink-safe, size-capped (64 bytes), whitelist-validated flag read. Returns null on any anomaly. Used by mode tracker's per-turn reinforcement to avoid injecting untrusted bytes into model context.76- `getFlagPath()` — resolves `$CLAUDE_CONFIG_DIR/.unslop-active`.7778### `hooks/unslop-activate.js` — SessionStart hook7980Runs once per Claude Code session start. Three things:811. Writes the active mode to `$CLAUDE_CONFIG_DIR/.unslop-active` via `safeWriteFlag` (creates if missing)822. Emits unslop ruleset as hidden stdout — reads `skills/unslop/SKILL.md` at runtime, falls back to `rules/unslop-activate.md`, then to hardcoded rules833. Checks `settings.json` for statusline config; if missing, appends nudge to offer setup on first interaction8485Silent-fails on all filesystem errors — never blocks session start.8687### `hooks/unslop-mode-tracker.js` — UserPromptSubmit hook8889Reads JSON from stdin. Three responsibilities:9091**1. Slash-command activation.** If prompt starts with `/unslop`, writes mode to flag file via `safeWriteFlag`:92- `/unslop` → configured default (see `unslop-config.js`, defaults to `balanced`)93- `/unslop subtle` → `subtle`94- `/unslop balanced` → `balanced`95- `/unslop full` → `full`96- `/unslop voice-match` → `voice-match`97- `/unslop anti-detector` → `anti-detector`98- `/unslop-commit` → `commit`99- `/unslop-review` → `review`100101**2. Natural-language activation/deactivation.** Matches phrases like "activate unslop", "turn on unslop mode", "humanize this", "make this sound human" and writes the configured default mode. Matches "stop unslop", "disable unslop", "normal mode", "robotic mode" and deletes the flag file.102103**3. Per-turn reinforcement.** When flag is set to a non-independent mode (i.e. not `commit`/`review`), emits a small `hookSpecificOutput` JSON reminder so the model keeps unslop style after other plugins inject competing instructions mid-conversation. The full ruleset comes from SessionStart — this is an attention anchor.104105### `hooks/unslop-statusline.sh` — Statusline badge106107Reads flag file at `$CLAUDE_CONFIG_DIR/.unslop-active`. Security hardened: refuses symlinks, caps read at 64 bytes, strips non-alphanumeric characters, whitelists valid modes. Outputs colored badge string for Claude Code statusline:108- `balanced` or empty → `[unslop]` (green)109- Anything else → `[unslop:<MODE_UPPERCASED>]` (green)110111PowerShell counterpart at `hooks/unslop-statusline.ps1` for Windows.112113### Hook installation114115**Plugin install** — hooks wired automatically by plugin system.116117**Standalone install** — `hooks/install.sh` (macOS/Linux) or `hooks/install.ps1` (Windows) copies hook files into `$CLAUDE_CONFIG_DIR/hooks/` and patches `settings.json` to register SessionStart and UserPromptSubmit hooks plus statusline. Supports `--force` for reinstall, checks idempotency, backs up settings.json.118119**Uninstall** — `hooks/uninstall.sh` / `hooks/uninstall.ps1` removes hook files and patches settings.json.120121**Hook safety rules:**122123- Hooks must never break the session. Catch all errors; silent-fail on filesystem errors.124- Hooks must be fast (<200ms). No network calls. No reading large files.125- Hooks must work on first install with no config. Config is opt-in.126- Any new flag file write must go through `safeWriteFlag()` in `unslop-config.js`. Direct `fs.writeFileSync` on predictable user-owned paths reopens the symlink-clobber attack surface.127- Hooks must respect `CLAUDE_CONFIG_DIR` env var, not hardcode `~/.claude`. Same for install/uninstall/statusline scripts.128129## Skills130131Markdown files with YAML frontmatter:132133```yaml134---135name: unslop136description: >137 ...138---139```140141`description` is the activation hint shown to the model. Keep it ≤200 words and include trigger phrases.142143The body is the operational spec. Sections we use consistently:144145- `## Persistence` — when the skill turns on/off146- `## Rules` — what to drop, what to keep147- `## Intensity` — modes and their effects148- `## Auto-Clarity` — when to suspend unslop style149- `## Boundaries` — hard limits150151## unslop Python package152153Lives in `unslop/scripts/`. The package is split:154155- `cli.py` — argparse-style CLI (no external deps)156- `detect.py` — file type and sensitivity detection157- `humanize.py` — core logic (deterministic regex + LLM mode)158- `validate.py` — preserve check (code/URL/heading) + AI-ism residual check159- `benchmark.py` — quality benchmark across a directory of samples160- `reasoning.py` — agent reasoning-trace stripper (`<thinking>`, `## Reasoning`). Opt-in via `--strip-reasoning`161- `surprisal.py` — optional local-LM DivEye reading. Opt-in via `--surprisal-variance`; requires `pip install torch transformers`162- `stylometry.py` — deterministic voice-match signal extraction (incl. DivEye proxies)163- `style_memory.py` — persisted voice profile storage (security-hardened)164- `structural.py` — Phase 1 structural pass165- `soul.py` — Phase 5 soul / contraction pass166- `detector.py` — optional AI-text detector feedback loop167- `fetch_detectors.py` — one-shot HF weight fetcher for `detector.py`168169**Add a new AI-ism**: edit `STOCK_VOCAB`, `HEDGING_OPENERS`, `SYCOPHANCY`, `PERFORMATIVE`, or `TRANSITION_TICS` in `humanize.py` AND add a corresponding pattern to `AI_ISMS` in `validate.py` so the validator catches additions. Add a test in `tests/unslop/test_humanize.py`.170171**Preservation is non-negotiable.** Every regex must run inside `_protect()` placeholders or be guaranteed to match only natural-language prose. `_protect` currently covers, in order: YAML frontmatter, fenced code, indented code, tables, blockquotes, headings, markdown links, inline code, bare URLs, quoted single-word examples (`"delve"`, use/mention distinction). The `TestPreservation` suite in `test_humanize.py` is the contract; the validator in `validate.py` byte-compares each protected category between input and output and fails the run on any mutation.172173**Per-paragraph em-dash cap has a list carve-out.** `_cap_em_dashes_per_paragraph` splits on blank lines, then for paragraphs that are pure lists (every non-blank line starts with `-`, `*`, `+`, or `N.`) it treats each list item as its own em-dash paragraph. Without this, a 5-bullet list where each bullet used a single em-dash would silently lose the dashes in bullets 3–5.174175## Tests176177```bash178python3 -m pytest tests/unslop/179```180181The deterministic suite must pass on every change. LLM tests are opt-in via `UNSLOP_RUN_LLM_TESTS=1` (cost API credits).182183## Adding a sub-skill1841851. Create `skills/<name>/SKILL.md` with frontmatter + body.1862. Create `commands/<name>.toml` if it gets a slash command.1873. Add the skill to the host manifest only when that host requires explicit skill or command entries. Claude Code hooks currently discover the repo's `skills/` and `commands/` files without listing them in `.claude-plugin/plugin.json`.1884. Add sync mappings in `scripts/sync-mirrors.sh`, then add trigger paths in `.github/workflows/sync.yml`.1895. Document the skill in `skills/unslop-help/SKILL.md` (the reference card).1906. Add a row to the README sub-skills table.191192## Voice193194The unslop voice we keep in our own docs: direct, specific, kind, no AI-isms. We eat our own dog food. If the README opens with "Great question!", we have failed.195196## Security197198- The Python scripts refuse sensitive paths (`.env*`, `*.pem`, `~/.ssh/`, etc.) before any read or API call.199- LLM mode optionally subprocesses the `claude` CLI when no `ANTHROPIC_API_KEY` is set. `subprocess.run` is always called with `shell=False` and a fixed argument list.200- File size cap: 500 KB. See `unslop/scripts/detect.py`.201- See `unslop/SECURITY.md` for the full Snyk rationale.202
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| MohamedAbdallah-14/unslop.clinerules/unslop.md · 94 | Cline rules | no sections | 30/100 | 14 days ago | |
| MohamedAbdallah-14/unslop.cursor/rules/unslop.mdc · 94 | Cursor rules | no sections | 30/100 | 14 days ago | |
| MohamedAbdallah-14/unslopAGENTS.md · 94 | AGENTS.md | testgitapiagent-behaviour | 64/100 | 14 days ago | |
| MohamedAbdallah-14/unslop.github/copilot-instructions.md · 94 | Copilot instructions | gitagent-behaviour | 30/100 | 14 days ago | |
| MohamedAbdallah-14/unslop.windsurf/rules/unslop.md · 94 | Windsurf rules | no sections | 30/100 | 14 days ago | |
| MohamedAbdallah-14/unslopGEMINI.md · 94 | GEMINI.md | no sections | 44/100 | 14 days ago |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| dotCMS/corecore-web/CLAUDE.md · 949 | CLAUDE.md | teststylearchtesting-strategy+3 | 100/100 | 14 days ago | |
| tyrchen/geektime-bootcamp-aiw7/genslides/backend/CLAUDE.md · 230 | CLAUDE.md | testlint-formatstylearch+6 | 100/100 | 9 days ago | |
| Adit-Jain-srm/NightmareNetCLAUDE.md · 46 | CLAUDE.md | buildtestlint-formatstyle+6 | 100/100 | 14 days ago | |
| dotCMS/coreCLAUDE.md · 949 | CLAUDE.md | setupbuildteststyle+7 | 99/100 | today | |
| dotCMS/corecore-web/libs/sdk/client/CLAUDE.md · 949 | CLAUDE.md | setupbuildtestlint-format+9 | 97/100 | 14 days ago | |
| dotCMS/corecore-web/libs/sdk/react/CLAUDE.md · 949 | CLAUDE.md | setupbuildtestlint-format+9 | 97/100 | 14 days ago | |
| supabase/supabase.claude/CLAUDE.md · 108k | CLAUDE.md | testlint-formatstylearch+1 | 97/100 | 14 days ago | |
| modelcontextprotocol/serversCLAUDE.md · 90k | CLAUDE.md | setupbuildtestlint-format+6 | 97/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/mohamedabdallah-14-unslop-claude)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.