One skill package for coding agents: write the least code that works, then delete the slop that crept in anyway.
/lazy commands.(A renamed hard fork of two upstream projects; this package is standalone and self-contained.)
For upstream comparisons and selective ports, follow the update procedure and record the reviewed revisions and local differences in UPSTREAM.md.
Same ruleset, five levels of wiring — pick whatever your agent supports.
| Tier | Platforms | What you get | Files |
|---|---|---|---|
| Full hooks | Claude Code, Codex | Compact ruleset injected at session and subagent start, /lazy level switching, slop-check auto-run after every Write/Edit | hooks/lazy-clean.json via .claude-plugin/plugin.json and .codex-plugin/plugin.json |
| Plugin | OpenCode | Ruleset injected every turn plus nine slash commands | .opencode/ + opencode.json + hooks/ + skills/ — the plugin loads the shared builder from hooks/, so copying only .opencode/ gives you a plugin that fails to load |
| Rules file | Cursor, Copilot | Always-on ruleset for all seven supported languages; run the TS/JS-only checker by hand after TS/JS changes | .cursor/rules/lazy-clean.mdc, .github/copilot-instructions.md |
AGENTS.md | Everything else that reads it — Codex, Zed, Amp, Jules | The compact ruleset plus the post-edit checker step | AGENTS.md |
| Skills only | Anything that reads ~/.claude/skills | Every skill on demand, no automation | skills/ |
Only the Claude Code and Codex tiers run the checker automatically. Everywhere else run it yourself, from wherever the skills live — node ~/.claude/skills/slop-check/scripts/check.mjs <changed files> after the skills-only install below, or node skills/slop-check/scripts/check.mjs <changed files> from a checkout.
Qoder and VS Code Copilot are detected by the hooks and get the right output shape, but neither is wired up here as its own tier. Upstream also ships adapters this fork skips (MCP server, pi extension, Hermes, Devin, openclaw). Add them from upstream if you need them.
The rulesets cover TypeScript, JavaScript, Java, Python, Ruby, Rust, and Go. The agent detects the ones your project actually uses, reads their pinned or installed versions, and keeps advice compatible with them. If a needed version fact cannot be checked, it says so instead of guessing; latest-release research is only used when current-version advice is requested.
The bundled checker reads source text rather than calling the compiler, so it
works the same on every TypeScript version, including TypeScript 7. It stays TS/JS-only; the other five languages get the manual review, because a zero-dependency scanner is not a parser.
HTML is not scanned either: extract inline <script> code to a temporary .js
or report a manual review. Zero files checked is no coverage, not a clean result.
TypeScript/JavaScript and Python also get a pre-finish reference with before/after
examples: TS/JS checks cover
TypeScript 6/7 (the native tsc: removed tsconfig options, new defaults, and the
TypeScript 6 alias API-based tools still need), module shape, exports, import-time side effects, discriminated unions, and
boundary parsing; Python checks cover
version gates, the project's configured linter and type checker, module shape,
dataclasses and Protocol, and the idioms that silently change behavior
(mutable defaults, if not x, bare except:). The rules files inline the key
points for agents that never open a reference.
The rulesets think before coding, state material assumptions when they matter, match existing style, cut only task-owned orphans, and define a verifiable goal. One-caller helpers stay when they carry real value (a domain name, tricky logic, an isolated side effect, test or readability value, or a framework contract). Non-trivial changed logic needs behavior, edge, and failure coverage; mutation evidence is optional when existing red-green checks already prove the risky regression, and never justifies a new dependency.
lazy-verify is an explicitly invoked skill and OpenCode command, not a lazy
intensity or hook. Fix checks for the approved assertion failure before and
a pass after. Preserve checks the same approved behavior on both snapshots.
Neither a successful project command nor a clean static scan is assertion-level
evidence; execution, behavior, supporting checks, gate and applicability are
reported separately.
The dependency-free Node >=18 bridge is self-contained under
skills/lazy-verify/, including skills-only copies.
Rules-only users can invoke node /installed/skills/lazy-verify/scripts/verify.mjs
directly; a native slash command depends on the client. It needs an explicitly
selected, reviewed local engine and policy. No engine is installed/downloaded
automatically. A separate approved Node executable can run a Node 24 engine
without changing lazy-clean's runtime or private package status.
No real engine is qualified yet. Bridge fixtures do not establish behavioral correctness or release readiness. Planned engine qualification is Linux/macOS on Node 24; Windows target execution returns an explicit unsupported result. Core Node 18/22 and Windows checks remain unchanged. Existing usage works without verification installed; missing prerequisites cannot pass a required gate.
Use explicit base/head selectors (worktree for actual uncommitted edits), a
reviewed contract and --trust-code. Local execution is not a security sandbox.
report renders recorded evidence without executing it; replay uses fresh
policy selection and saved exact inputs. Generated .lazy-verify/runs/ output
is private/ignored in this repository; contracts remain reviewable. See the
installed protocol reference for
commands, policy schema, limits and exits, and the
RFC for engine/release acceptance gates.
Invoke /layz-test <files or change> (Codex: @layz-test) to map behaviors,
find reproducible bugs, run applicable checks with existing tools, and add missing
regression coverage.
The report ends with manual steps and why automation cannot settle each check;
missing dependencies or browsers are listed as blocked automation. Passing
checks apply only to the stated scope. This instruction-only skill adds no
runner or dependencies and does not change lazy mode.
Invoke /test-quality-review <tests or change> (Codex: @test-quality-review)
to review pointless tests or assertions, implementation coupling, and weak
oracles that can pass despite broken behavior. Findings need concrete evidence
and a recommendation to keep, strengthen, replace, or remove the check; mocks,
snapshots, and shape assertions are not inherently wrong when they verify a
real contract. This instruction-only review
is one-shot and independent of lazy mode. With no narrower scope it reviews the
entire suite, records reviewed and unfinished scope, and can prioritize recent
additions without silently excluding older tests. An explicit recent-tests audit
uses an established base revision or date.
The reviewer reports only. When findings are applied, a separate fresh-context agent receives the self-contained report and makes tests-only changes. It may delete genuinely pointless tests without replacement, but must explain each deletion in its final report and preserve useful coverage. It must not change production code to make strengthened tests pass; exposed product bugs are reported separately with their failing reproducer. No fixer starts automatically for a review-only request.
No npm packages or plugin needed. Install with GitHub CLI to keep source metadata for future updates:
gh skill install JustasMonkev/lazy-clean --all --agent claude-code --scope user
For Codex, use --agent codex instead. Omit --scope user for a project-local
installation. GitHub CLI selects the latest tagged release, or the default
branch when there are no releases.
Check and apply updates to that installation:
gh skill update --dir ~/.claude/skills --dry-run \
layz-test lazy lazy-audit lazy-clean lazy-debt lazy-gain lazy-help \
lazy-review lazy-verify slop-check test-quality-review
gh skill update --dir ~/.claude/skills \
layz-test lazy lazy-audit lazy-clean lazy-debt lazy-gain lazy-help \
lazy-review lazy-verify slop-check test-quality-review
For user-scope Codex skills, use --dir ~/.agents/skills. For project-scope
Claude Code use --dir .claude/skills; for project-scope Codex use
--dir .agents/skills. These explicit directories also avoid scanning this
checkout's source skills/ directory, which has no installation metadata.
If you previously copied these skills manually, back up any local edits, then reinstall once with metadata:
gh skill install JustasMonkev/lazy-clean --all --agent claude-code --scope user --force
These commands install and update this repository's skills only.
Without GitHub CLI, manual copying still works, but does not enable
gh skill update:
cp -R /path/to/lazy-clean/skills/* ~/.claude/skills/
That gives you all 11 skills (lazy-clean, lazy, lazy-review, lazy-audit, lazy-debt, lazy-gain, lazy-help, slop-check, lazy-verify, layz-test, test-quality-review). Claude picks them up by description or by /lazy-clean etc.; lazy-help, lazy-gain, and lazy-verify are slash-only in Claude Code (disable-model-invocation), so their descriptions cost no context. The checker script travels inside the slop-check skill and runs with plain node — zero dependencies.
What you DON'T get in skills-only mode: the automatic parts (ruleset injected every session, checker auto-run after every edit). Those need the hooks — install as a plugin for that:
Local checkout:
claude --plugin-dir /path/to/lazy-clean
Or add the checkout as a marketplace and enable it with /plugin:
claude plugin marketplace add /path/to/lazy-clean
Requires node 18+ on PATH. No dependencies to install.
| Event | What happens |
|---|---|
SessionStart | startup/clear initialize the default; resume/compact restore the session level |
SubagentStart | same ruleset injected into the subagent, except read-only Explore agents |
UserPromptSubmit | /lazy … commands parsed, level flag updated |
PostToolUse on Write/Edit/MultiEdit | skills/slop-check/scripts/check.mjs runs on the edited file |
Every subagent except the read-only Explore agents gets the ruleset (about 2,000 tokens on each of its requests). To choose which agent_types get it, set LAZY_SUBAGENT_MATCHER to a case-insensitive regex; . injects it into Explore too.
The checker only looks at .ts .tsx .mts .cts .js .jsx .mjs .cjs; anything else is skipped silently. Files written through Bash — heredocs, sed -i, codemods — are not seen by the hook at all; run the checker on those yourself.
Findings are advisory — they arrive as additionalContext, never as a block, and the hook always exits 0. A failed checker run reports check failed; it does not claim the edit was clean. It reports findings on the lines attributed to that edit and counts findings elsewhere in the file whose origin is unknown. Those other findings may come from earlier edits in the same task; the final scan still covers them. Triage them per skills/slop-check/SKILL.md: fix real slop and report checked invariants for retained findings in the final response. Do not add code comments; remove nonessential comments from code you touch. Keep required license notices and functional tool directives. Never add SAFETY: or lazy: markers. Verify necessary functional suppressions and explain the evidence in the final response.
node skills/slop-check/scripts/check.mjs [paths...] [--json] [--summary] [--since=<ref>] [--disable=<rule-id>,...] [--explain=<rule-id>]
With no paths it scans the current directory. Exit code 1 means findings, 2 means a path could not be read, 0 means clean — so a failed scan is never mistaken for a clean one.
--since=<ref> keeps only findings on lines the diff against <ref> added. That is the whole adoption story for an existing codebase: there is no baseline file to generate or refresh, because git already holds the baseline.
node skills/slop-check/scripts/check.mjs --since=HEAD # before committing
node skills/slop-check/scripts/check.mjs --since=origin/main # in CI
Findings are grouped by whether the fix needs judgment: mechanical ones have a single correct answer, review ones are heuristics where "this is deliberate, leaving it" is a legitimate reply. A message shared by several findings is printed once, on the first. --summary replaces the finding list with the per-rule tally, which is the number that tells you whether a codebase is worth a full pass. The run summary line still prints; --json is the machine-readable form.
Assertion tallies display type assertion review. The legacy rule ID require-safety-comment-for-type-assertion remains accepted by --explain, --disable, and existing directives, and remains the ID in JSON output.
Emoji, sequencing comments, change-note comments, and apparently obvious documentation comments are review findings. Retain symbols required by a specification; put useful contracts and rationale in the final response. Existing SAFETY: and slop-check-ignore directives remain supported for compatibility, but new ones are not a remedy for findings.
--explain=<rule-id> prints one rule's reasoning — why it fires, a slop/instead pair, and when the rule is wrong — and runs no scan. Read it before rewriting code a finding landed on that you believe is correct:
node skills/slop-check/scripts/check.mjs --explain=no-json-clone
Array performance findings are review prompts too: no-reduce-accumulator-copy
detects repeated copies of reducer accumulators, including spread, and
no-array-filter-map checks adjacent eager passes on locally evidenced arrays.
These checks are conservative and have no autofix. Before rewriting, preserve
accumulator ownership, callback order and indexes, and sparse-array behavior.
Before finishing any TS/JS task, run node skills/slop-check/scripts/check.mjs --since=HEAD
from the repo root even if edit hooks ran. It includes new untracked files and
shell edits without fragile shell path splitting. Use the task base ref for
already-committed changes. Triage only the task's scope, not unrelated user edits.
Without Git, pass each changed path as a separate quoted argument.
The main and subagent prompts use the same compact rules. They include a brief
think → plan → check loop for multi-step work and a strong cut pass over the
task-owned diff without forcing net-negative feature changes. Every build
surface (the lazy and lazy-clean skills, the injected ruleset, the rules
files, and OpenCode's /lazy) ends with the same four-item finish checklist, checked against the diff rather
than memory: requested needs done and nothing unasked added, each changed line
traceable, tests that ran, and language checks applied. Detailed
risk checks are loaded for non-trivial
code changes, not every task. All levels preserve requested scope, existing
input formats, and the repo's test tools; none treats one-line code as a goal.
Run the AI behavior checks to compare fourteen core tasks with the
rules off/on, three trials each. A separate six-task SOLID set checks module
boundaries and contracts; see the design experiment. Compare correctness first, then time, cost,
and size for paired passing runs. This fork makes no measured improvement
claim without real comparable runs. npm test checks the benchmark machinery
without calling an AI service.
For a genuine false positive, verify the invariant and explain the evidence in the final response. Do not add suppression comments to make the scan clean. Remove ineffective existing ignores and address the underlying findings.
Existing justified slop-check-ignore directives remain supported for compatibility. They cover their line and the next and accept several rule IDs separated by commas. Existing slop-check-ignore-file directives in a file's first 10 lines cover the whole file. --disable=<rule-id>,... turns rules off for one run; it does not verify that a finding is harmless.
An existing ignore with no reason after --, an unknown rule ID, or a file-level directive below line 10 suppresses nothing and is reported as no-unjustified-ignore. The run summary counts suppressions; a clean result with suppressions is not evidence that the ignored code was checked.
Skills available: lazy, lazy-audit, lazy-debt, lazy-gain, lazy-help, lazy-review, slop-check, lazy-clean (the main workflow), lazy-verify, layz-test, test-quality-review.
/lazy lite # gentle
/lazy full # default
/lazy ultra # YAGNI extremist
/lazy # report current level
/lazy default <lite|full|ultra|off> sets the default for new sessions. When the
host supplies a session ID, each session retains its own level (including off)
across resume, compaction, and process restarts. Changing the default does not
change already initialized sessions. Subagents and the badge use the same session
state when the host supplies that identity.
On OpenCode upgrades, the first session needing initial state inherits the legacy global mode. Successful migration removes the global flag; later sessions use the configured default. Existing scoped modes are never overwritten.
Hosts without session IDs retain the legacy global flag: concurrent chats cannot be isolated there. On no-ID OpenCode, changing the default clears that global override and affects the current chat too; the command reports this explicitly. Session files are not expired by age, because an old session can still be resumed.
The Bash and PowerShell statusline launchers use the shared Node state/config reader. The plugin ships a statusline script that shows the active level ([LAZY], [LAZY:ULTRA]). It is not wired up automatically: on first session the hook offers to add a statusLine entry to your settings.json pointing at hooks/lazy-statusline.sh (or .ps1 on Windows), and it makes that offer at most once.
Hide the badge while keeping lazy active with LAZY_HIDE_STATUS=1, or "hideStatus": true in ~/.config/lazy/config.json (%APPDATA%\lazy\config.json on Windows).
/lazy off (or say "stop lazy" / "normal mode"). It stays off in that session, including after resume/compaction; new sessions use the default.PostToolUse entry from hooks/lazy-clean.json./plugin, or drop the --plugin-dir flag.npm test # rule, CLI, and hook suites — no dependencies
npm run slop-check # the checker over this repo, which it has to survive
JavaScript
100.0%
One skill package for coding agents: write the least code that works, then delete the slop that crept in anyway.
/lazy commands.(A renamed hard fork of two upstream projects; this package is standalone and self-contained.)
For upstream comparisons and selective ports, follow the update procedure and record the reviewed revisions and local differences in UPSTREAM.md.
Same ruleset, five levels of wiring — pick whatever your agent supports.
| Tier | Platforms | What you get | Files |
|---|---|---|---|
| Full hooks | Claude Code, Codex | Compact ruleset injected at session and subagent start, /lazy level switching, slop-check auto-run after every Write/Edit | hooks/lazy-clean.json via .claude-plugin/plugin.json and .codex-plugin/plugin.json |
| Plugin | OpenCode | Ruleset injected every turn plus nine slash commands | .opencode/ + opencode.json + hooks/ + skills/ — the plugin loads the shared builder from hooks/, so copying only .opencode/ gives you a plugin that fails to load |
| Rules file | Cursor, Copilot | Always-on ruleset for all seven supported languages; run the TS/JS-only checker by hand after TS/JS changes | .cursor/rules/lazy-clean.mdc, .github/copilot-instructions.md |
AGENTS.md | Everything else that reads it — Codex, Zed, Amp, Jules | The compact ruleset plus the post-edit checker step | AGENTS.md |
| Skills only | Anything that reads ~/.claude/skills | Every skill on demand, no automation | skills/ |
Only the Claude Code and Codex tiers run the checker automatically. Everywhere else run it yourself, from wherever the skills live — node ~/.claude/skills/slop-check/scripts/check.mjs <changed files> after the skills-only install below, or node skills/slop-check/scripts/check.mjs <changed files> from a checkout.
Qoder and VS Code Copilot are detected by the hooks and get the right output shape, but neither is wired up here as its own tier. Upstream also ships adapters this fork skips (MCP server, pi extension, Hermes, Devin, openclaw). Add them from upstream if you need them.
The rulesets cover TypeScript, JavaScript, Java, Python, Ruby, Rust, and Go. The agent detects the ones your project actually uses, reads their pinned or installed versions, and keeps advice compatible with them. If a needed version fact cannot be checked, it says so instead of guessing; latest-release research is only used when current-version advice is requested.
The bundled checker reads source text rather than calling the compiler, so it
works the same on every TypeScript version, including TypeScript 7. It stays TS/JS-only; the other five languages get the manual review, because a zero-dependency scanner is not a parser.
HTML is not scanned either: extract inline <script> code to a temporary .js
or report a manual review. Zero files checked is no coverage, not a clean result.
TypeScript/JavaScript and Python also get a pre-finish reference with before/after
examples: TS/JS checks cover
TypeScript 6/7 (the native tsc: removed tsconfig options, new defaults, and the
TypeScript 6 alias API-based tools still need), module shape, exports, import-time side effects, discriminated unions, and
boundary parsing; Python checks cover
version gates, the project's configured linter and type checker, module shape,
dataclasses and Protocol, and the idioms that silently change behavior
(mutable defaults, if not x, bare except:). The rules files inline the key
points for agents that never open a reference.
The rulesets think before coding, state material assumptions when they matter, match existing style, cut only task-owned orphans, and define a verifiable goal. One-caller helpers stay when they carry real value (a domain name, tricky logic, an isolated side effect, test or readability value, or a framework contract). Non-trivial changed logic needs behavior, edge, and failure coverage; mutation evidence is optional when existing red-green checks already prove the risky regression, and never justifies a new dependency.
lazy-verify is an explicitly invoked skill and OpenCode command, not a lazy
intensity or hook. Fix checks for the approved assertion failure before and
a pass after. Preserve checks the same approved behavior on both snapshots.
Neither a successful project command nor a clean static scan is assertion-level
evidence; execution, behavior, supporting checks, gate and applicability are
reported separately.
The dependency-free Node >=18 bridge is self-contained under
skills/lazy-verify/, including skills-only copies.
Rules-only users can invoke node /installed/skills/lazy-verify/scripts/verify.mjs
directly; a native slash command depends on the client. It needs an explicitly
selected, reviewed local engine and policy. No engine is installed/downloaded
automatically. A separate approved Node executable can run a Node 24 engine
without changing lazy-clean's runtime or private package status.
No real engine is qualified yet. Bridge fixtures do not establish behavioral correctness or release readiness. Planned engine qualification is Linux/macOS on Node 24; Windows target execution returns an explicit unsupported result. Core Node 18/22 and Windows checks remain unchanged. Existing usage works without verification installed; missing prerequisites cannot pass a required gate.
Use explicit base/head selectors (worktree for actual uncommitted edits), a
reviewed contract and --trust-code. Local execution is not a security sandbox.
report renders recorded evidence without executing it; replay uses fresh
policy selection and saved exact inputs. Generated .lazy-verify/runs/ output
is private/ignored in this repository; contracts remain reviewable. See the
installed protocol reference for
commands, policy schema, limits and exits, and the
RFC for engine/release acceptance gates.
Invoke /layz-test <files or change> (Codex: @layz-test) to map behaviors,
find reproducible bugs, run applicable checks with existing tools, and add missing
regression coverage.
The report ends with manual steps and why automation cannot settle each check;
missing dependencies or browsers are listed as blocked automation. Passing
checks apply only to the stated scope. This instruction-only skill adds no
runner or dependencies and does not change lazy mode.
Invoke /test-quality-review <tests or change> (Codex: @test-quality-review)
to review pointless tests or assertions, implementation coupling, and weak
oracles that can pass despite broken behavior. Findings need concrete evidence
and a recommendation to keep, strengthen, replace, or remove the check; mocks,
snapshots, and shape assertions are not inherently wrong when they verify a
real contract. This instruction-only review
is one-shot and independent of lazy mode. With no narrower scope it reviews the
entire suite, records reviewed and unfinished scope, and can prioritize recent
additions without silently excluding older tests. An explicit recent-tests audit
uses an established base revision or date.
The reviewer reports only. When findings are applied, a separate fresh-context agent receives the self-contained report and makes tests-only changes. It may delete genuinely pointless tests without replacement, but must explain each deletion in its final report and preserve useful coverage. It must not change production code to make strengthened tests pass; exposed product bugs are reported separately with their failing reproducer. No fixer starts automatically for a review-only request.
No npm packages or plugin needed. Install with GitHub CLI to keep source metadata for future updates:
gh skill install JustasMonkev/lazy-clean --all --agent claude-code --scope user
For Codex, use --agent codex instead. Omit --scope user for a project-local
installation. GitHub CLI selects the latest tagged release, or the default
branch when there are no releases.
Check and apply updates to that installation:
gh skill update --dir ~/.claude/skills --dry-run \
layz-test lazy lazy-audit lazy-clean lazy-debt lazy-gain lazy-help \
lazy-review lazy-verify slop-check test-quality-review
gh skill update --dir ~/.claude/skills \
layz-test lazy lazy-audit lazy-clean lazy-debt lazy-gain lazy-help \
lazy-review lazy-verify slop-check test-quality-review
For user-scope Codex skills, use --dir ~/.agents/skills. For project-scope
Claude Code use --dir .claude/skills; for project-scope Codex use
--dir .agents/skills. These explicit directories also avoid scanning this
checkout's source skills/ directory, which has no installation metadata.
If you previously copied these skills manually, back up any local edits, then reinstall once with metadata:
gh skill install JustasMonkev/lazy-clean --all --agent claude-code --scope user --force
These commands install and update this repository's skills only.
Without GitHub CLI, manual copying still works, but does not enable
gh skill update:
cp -R /path/to/lazy-clean/skills/* ~/.claude/skills/
That gives you all 11 skills (lazy-clean, lazy, lazy-review, lazy-audit, lazy-debt, lazy-gain, lazy-help, slop-check, lazy-verify, layz-test, test-quality-review). Claude picks them up by description or by /lazy-clean etc.; lazy-help, lazy-gain, and lazy-verify are slash-only in Claude Code (disable-model-invocation), so their descriptions cost no context. The checker script travels inside the slop-check skill and runs with plain node — zero dependencies.
What you DON'T get in skills-only mode: the automatic parts (ruleset injected every session, checker auto-run after every edit). Those need the hooks — install as a plugin for that:
Local checkout:
claude --plugin-dir /path/to/lazy-clean
Or add the checkout as a marketplace and enable it with /plugin:
claude plugin marketplace add /path/to/lazy-clean
Requires node 18+ on PATH. No dependencies to install.
| Event | What happens |
|---|---|
SessionStart | startup/clear initialize the default; resume/compact restore the session level |
SubagentStart | same ruleset injected into the subagent, except read-only Explore agents |
UserPromptSubmit | /lazy … commands parsed, level flag updated |
PostToolUse on Write/Edit/MultiEdit | skills/slop-check/scripts/check.mjs runs on the edited file |
Every subagent except the read-only Explore agents gets the ruleset (about 2,000 tokens on each of its requests). To choose which agent_types get it, set LAZY_SUBAGENT_MATCHER to a case-insensitive regex; . injects it into Explore too.
The checker only looks at .ts .tsx .mts .cts .js .jsx .mjs .cjs; anything else is skipped silently. Files written through Bash — heredocs, sed -i, codemods — are not seen by the hook at all; run the checker on those yourself.
Findings are advisory — they arrive as additionalContext, never as a block, and the hook always exits 0. A failed checker run reports check failed; it does not claim the edit was clean. It reports findings on the lines attributed to that edit and counts findings elsewhere in the file whose origin is unknown. Those other findings may come from earlier edits in the same task; the final scan still covers them. Triage them per skills/slop-check/SKILL.md: fix real slop and report checked invariants for retained findings in the final response. Do not add code comments; remove nonessential comments from code you touch. Keep required license notices and functional tool directives. Never add SAFETY: or lazy: markers. Verify necessary functional suppressions and explain the evidence in the final response.
node skills/slop-check/scripts/check.mjs [paths...] [--json] [--summary] [--since=<ref>] [--disable=<rule-id>,...] [--explain=<rule-id>]
With no paths it scans the current directory. Exit code 1 means findings, 2 means a path could not be read, 0 means clean — so a failed scan is never mistaken for a clean one.
--since=<ref> keeps only findings on lines the diff against <ref> added. That is the whole adoption story for an existing codebase: there is no baseline file to generate or refresh, because git already holds the baseline.
node skills/slop-check/scripts/check.mjs --since=HEAD # before committing
node skills/slop-check/scripts/check.mjs --since=origin/main # in CI
Findings are grouped by whether the fix needs judgment: mechanical ones have a single correct answer, review ones are heuristics where "this is deliberate, leaving it" is a legitimate reply. A message shared by several findings is printed once, on the first. --summary replaces the finding list with the per-rule tally, which is the number that tells you whether a codebase is worth a full pass. The run summary line still prints; --json is the machine-readable form.
Assertion tallies display type assertion review. The legacy rule ID require-safety-comment-for-type-assertion remains accepted by --explain, --disable, and existing directives, and remains the ID in JSON output.
Emoji, sequencing comments, change-note comments, and apparently obvious documentation comments are review findings. Retain symbols required by a specification; put useful contracts and rationale in the final response. Existing SAFETY: and slop-check-ignore directives remain supported for compatibility, but new ones are not a remedy for findings.
--explain=<rule-id> prints one rule's reasoning — why it fires, a slop/instead pair, and when the rule is wrong — and runs no scan. Read it before rewriting code a finding landed on that you believe is correct:
node skills/slop-check/scripts/check.mjs --explain=no-json-clone
Array performance findings are review prompts too: no-reduce-accumulator-copy
detects repeated copies of reducer accumulators, including spread, and
no-array-filter-map checks adjacent eager passes on locally evidenced arrays.
These checks are conservative and have no autofix. Before rewriting, preserve
accumulator ownership, callback order and indexes, and sparse-array behavior.
Before finishing any TS/JS task, run node skills/slop-check/scripts/check.mjs --since=HEAD
from the repo root even if edit hooks ran. It includes new untracked files and
shell edits without fragile shell path splitting. Use the task base ref for
already-committed changes. Triage only the task's scope, not unrelated user edits.
Without Git, pass each changed path as a separate quoted argument.
The main and subagent prompts use the same compact rules. They include a brief
think → plan → check loop for multi-step work and a strong cut pass over the
task-owned diff without forcing net-negative feature changes. Every build
surface (the lazy and lazy-clean skills, the injected ruleset, the rules
files, and OpenCode's /lazy) ends with the same four-item finish checklist, checked against the diff rather
than memory: requested needs done and nothing unasked added, each changed line
traceable, tests that ran, and language checks applied. Detailed
risk checks are loaded for non-trivial
code changes, not every task. All levels preserve requested scope, existing
input formats, and the repo's test tools; none treats one-line code as a goal.
Run the AI behavior checks to compare fourteen core tasks with the
rules off/on, three trials each. A separate six-task SOLID set checks module
boundaries and contracts; see the design experiment. Compare correctness first, then time, cost,
and size for paired passing runs. This fork makes no measured improvement
claim without real comparable runs. npm test checks the benchmark machinery
without calling an AI service.
For a genuine false positive, verify the invariant and explain the evidence in the final response. Do not add suppression comments to make the scan clean. Remove ineffective existing ignores and address the underlying findings.
Existing justified slop-check-ignore directives remain supported for compatibility. They cover their line and the next and accept several rule IDs separated by commas. Existing slop-check-ignore-file directives in a file's first 10 lines cover the whole file. --disable=<rule-id>,... turns rules off for one run; it does not verify that a finding is harmless.
An existing ignore with no reason after --, an unknown rule ID, or a file-level directive below line 10 suppresses nothing and is reported as no-unjustified-ignore. The run summary counts suppressions; a clean result with suppressions is not evidence that the ignored code was checked.
Skills available: lazy, lazy-audit, lazy-debt, lazy-gain, lazy-help, lazy-review, slop-check, lazy-clean (the main workflow), lazy-verify, layz-test, test-quality-review.
/lazy lite # gentle
/lazy full # default
/lazy ultra # YAGNI extremist
/lazy # report current level
/lazy default <lite|full|ultra|off> sets the default for new sessions. When the
host supplies a session ID, each session retains its own level (including off)
across resume, compaction, and process restarts. Changing the default does not
change already initialized sessions. Subagents and the badge use the same session
state when the host supplies that identity.
On OpenCode upgrades, the first session needing initial state inherits the legacy global mode. Successful migration removes the global flag; later sessions use the configured default. Existing scoped modes are never overwritten.
Hosts without session IDs retain the legacy global flag: concurrent chats cannot be isolated there. On no-ID OpenCode, changing the default clears that global override and affects the current chat too; the command reports this explicitly. Session files are not expired by age, because an old session can still be resumed.
The Bash and PowerShell statusline launchers use the shared Node state/config reader. The plugin ships a statusline script that shows the active level ([LAZY], [LAZY:ULTRA]). It is not wired up automatically: on first session the hook offers to add a statusLine entry to your settings.json pointing at hooks/lazy-statusline.sh (or .ps1 on Windows), and it makes that offer at most once.
Hide the badge while keeping lazy active with LAZY_HIDE_STATUS=1, or "hideStatus": true in ~/.config/lazy/config.json (%APPDATA%\lazy\config.json on Windows).
/lazy off (or say "stop lazy" / "normal mode"). It stays off in that session, including after resume/compaction; new sessions use the default.PostToolUse entry from hooks/lazy-clean.json./plugin, or drop the --plugin-dir flag.npm test # rule, CLI, and hook suites — no dependencies
npm run slop-check # the checker over this repo, which it has to survive
JavaScript
100.0%