CleanSlop CLI
Readiness scans from your coding agent. The CLI starts a CleanSlop scan of your repo, waits for it, and hands the report back so the agent can fix what it finds. Published as @cleanslop/cli (bin cleanslop).
- Setup guide and FAQ: https://cleanslop.com/agents
- Agent guide (Markdown): https://cleanslop.com/agents.md
- Prefer MCP? Install the remote server: https://cleanslop.com/mcp
New in 0.2.0
- Rescans check only what changed.
cleanslop scanbuilds on the last scan of the same branch, or of the same uploaded folder, and costs only the files changed since. It prints which scan it built on, or why it ran a full scan.--fullscans everything again; when nothing changed, it asks before doing that. - Credits. Balances, plans and packs are counted in credits. A scan priced over 4 credits stops before it is charged and asks; after a yes, rerun with
--confirm-credits <credits>. - The Claude Code plugin moved to cleanslop/skills.
Everything else is in CHANGELOG.md.
Quick start
npx -y @cleanslop/cli scan
Run it from a git checkout whose HEAD is pushed to github.com. Then npx -y @cleanslop/cli setup installs the skill or rules for Claude Code, Cursor and Codex so your agent runs it for you.
Requires Node 22 or later (Node 20 is end-of-life; npm warns there). Zero runtime dependencies. Link commands shell out to link-cli 1.2.0 or later: CLEANSLOP_LINK_CLI (an older one is an error), else link-cli on PATH when it is new enough, else the pinned npx @stripe/[email protected]. link-cli runs from the CLI's config folder with the project's node_modules/.bin off PATH, so the repo you scan can't choose it; uploads pack with a built-in tar writer.
Commands
| Command | Purpose |
|---|---|
scan (default) | Resolve the github.com origin + HEAD and start a scan. It builds on the last scan of the branch (or of the uploaded folder) and costs only the files changed since. --wait waits for the report; --full scans everything again; --upload scans the local files instead of the pushed commit (after the human picks it); --confirm-credits <credits> approves a price over 4 credits, only after the human says yes; --force skips the same-commit dedupe |
login [--link [--agree]] [--no-wait | --resume] | RFC 8628 device flow. Prints verification_uri_complete and user_code. --no-wait stores the device code; --resume finishes it. --link signs up or signs in with Stripe Link through link-cli instead of GitHub; pass --agree only after the human says yes to the quoted terms question. Never prints the token. |
logout [--all] | Revoke server-side, delete this origin's credentials, and drop its pending GitHub login and Link payment. --all revokes every saved origin's token and deletes all local CleanSlop data (Link's own session and ~/.link-cli files stay; link-cli auth logout clears the session) |
whoami | Connected @login, token last4, plan with its monthly credits, and credits remaining (with what a scan costs). --json adds creditBalance |
status [id] [--wait] | Poll scan status |
report [id] [--format md|json] [--preview] | Fetch cleanslop.report.v1 (the whole list: limit=250). A final Markdown report with confirmed or needs-input findings is followed on stderr by a fix_findings question (Fix them / Show me first / Not now); scan does the same. Exit stays 0. |
setup | Idempotent skill/rules. Never logs in, never writes a token |
redeem <code> | Redeem a promo (invite) code the human gave you for bonus credits (POST /api/agent/v1/credits/redeem). One code per account; promo_invalid / promo_already_redeemed exit 12 with an ask_human block. |
credits buy --link [--pack p5|p15|p40] [--no-promo] [--no-wait | --resume] | Link account: buys a one-time credit pack from a Link approval (link-cli spend-request create), then POST /api/agent/v1/credits/purchases. --pack is required without a terminal (the human picks); a terminal defaults to p5. --no-promo skips the promo-code choice. --no-wait prints what to approve and exits 10; --resume continues it, saved in pending-spend-request.json. |
billing | Link account: POST /api/agent/v1/billing/sign-in-link has the server email a sign-in link to the account's Link address, where the human subscribes, buys credits or cancels a plan. Prints the masked address it went to, plus /signin/email?from=agent and the masked email to type if it does not arrive. When the server cannot send (email login off, rate limited) or is older (404, read webBilling from GET /me), it prints only the typed-address page. The CLI never sees the link. Exits 10 with an ask_human block; --json prints {sent, expiresAt | reason, webBilling}. Prints "Not available for this account" (exit 0) without webBilling. |
plan [starter|pro|max] | Link account: starts a monthly plan paid each month from a recurring Link approval (link-cli spend-request create --recurring-interval month), then POST /api/agent/v1/plans/purchases. Without a plan name an agent gets a link_plan question (Starter, Pro, Max with monthly prices, Not now). Same --no-wait / --resume flow as credits buy --link, saved in its own pending-plan-request.json. When CleanSlop offers no Link plans it does what billing does. Prints "Started the CleanSlop … plan" (exit 0). Change or cancel the plan with billing. |
Wait
--waitdefaults to 8 minutes when no duration is given.--wait 75mis the Claude Code background budget.- Durations:
30s,8m,1h. - Honour
pollAfterSec(10 pending/first pass, 20 review, 30 past p90); never poll faster than 3 seconds. Print the ETA while waiting. - At the deadline: exit 75 and print the ETA plus
cleanslop status <id> --wait.
Setup
Default is user scope:
| Agent | Path |
|---|---|
| Claude Code | ~/.claude/skills/cleanslop/SKILL.md |
| Cursor | ~/.cursor/rules/cleanslop.mdc |
| Codex | marker block in ~/.codex/AGENTS.md |
--project writes .cursor/rules/cleanslop.mdc and an AGENTS.md marker in the current repo. --dry-run / non-TTY without --yes only print the plan. --uninstall removes the marker blocks / owned files.
Skill / Cursor rules / AGENTS snippet are generated from assets/skill-core.md. The Claude Code plugin's SKILL.md in cleanslop/skills is rendered from the same file. Remote MCP is a separate install: see https://cleanslop.com/mcp.
Credentials
$XDG_CONFIG_HOME/cleanslop/credentials.jsonor~/.config/cleanslop/(Windows:%APPDATA%\cleanslop\)- Directory
0700, file0600 - Refuses to write inside the current git worktree
CLEANSLOP_TOKENandCLEANSLOP_ORIGINoverride the file / default origin (https://cleanslop.com)- The token is never printed;
whoamishows last4
Exit codes
| Code | Meaning |
|---|---|
| 0 | Done |
| 1 | Unexpected error |
| 2 | Usage or config |
| 10 | Human action (approve, install, reauth, or a question such as a scan price to confirm) |
| 11 | Payment (402) |
| 12 | Policy (waitlisted, beta, cap) |
| 13 | Source unavailable (dirty, unpushed, not github.com) |
| 20 | Scan failed server-side |
| 75 | Still running; resume command printed |
CLEANSLOP_ACTION_REQUIRED blocks go to stderr. Never open, approve, or pay. A block may end with a CLEANSLOP_QUESTION: JSON line (id, header, question, options[] with value, label, optional description, and run for the exact next command or next for a plain next step; neither means stop). Agents with a multiple-choice question tool (for example Claude Code's AskUserQuestion) should ask with it, using exactly those options, and never answer for the human. Consent questions never carry --agree.
Claude Code plugin
The plugin, which bundles the skill and the remote MCP server, lives in cleanslop/skills:
/plugin marketplace add cleanslop/skills
/plugin install cleanslop@cleanslop
The cleanslop marketplace in this repository still works; it now installs the plugin from cleanslop/skills.
Development
npm ci
npm test
npm run build
node dist/index.js scan
test/ uses node:test and c8 against a fake HTTP server. The coverage floor is 90% for lines, statements and functions, and 80% for branches. npm test also checks that the tree names no upstream-only hosts or paths (scripts/check-public.mjs).
This repository is a read-only mirror of the CLI's upstream source; see CONTRIBUTING.md for how pull requests land. Each sync to main stages the next patch release (scripts/release-version.mjs) with npm provenance, and a maintainer approves it under Staged Packages on npmjs.com, then publishes the GitHub release drafted from CHANGELOG.md. Do not npm publish by hand.