tristanmanchester/agent-skills

rust-anti-slop

Opinionated guardrails that reject low-evidence Rust patterns — unwrap/clone/Arc<Mutex> reflexes, silent error swallowing, lint suppression, stub completion.

First seen Aug 19, 2026

Installation

$ npx skills add tristanmanchester/agent-skills --skill rust-anti-slop

Summary

  • Opinionated guardrails that reject low-evidence Rust patterns — unwrap/clone/Arc<Mutex> reflexes, silent error swallowing, lint suppression, stub completion.
  • Use when writing or reviewing Rust code, or when asked to install anti-slop lint policy (workspace lints + clippy.toml) into a Rust repository.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from tristanmanchester/agent-skills · top by installs.

npx skills add tristanmanchester/agent-skills

Browse all from tristanmanchester/agent-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 3
Default branch main
Open issues 1
Status Active

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 10,027 B
  • docs SUMMARY.md 325 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 4 installs

SKILL.md

rust-anti-slop

Rust's compiler already rejects most of what a linter must catch in other languages. What remains — and what LLM-generated Rust reliably produces — is code that satisfies the compiler by discarding the evidence it asked for: .unwrap() discards fallibility, cloning past a borrow error discards the ownership analysis, a reflexive Arc<Mutex<T>> discards the sharing design, let = discards #[mustuse], #[allow] discards the diagnostic, todo!() fabricates completion, and an unargued unsafe impl Send fabricates thread-safety. None of these constructs is illegitimate in itself — each is illegitimate without its argument. This skill demands the argument.

Enforcement is layered:

  1. Mechanicalassets/workspace-lints.toml (a [workspace.lints]

table: cherry-picked clippy restriction lints plus rustc lints) and assets/clippy.toml (test exemptions, disallowed-* bans). No custom lint engine is needed; unlike TypeScript, the platform ships one.

  1. Prosereferences/rules.md: the rules no lint can express (clone

justification, expect-message quality, error-type doctrine, abstraction discipline). Read it before writing any substantial Rust.

The escape hatch for a specific, presently known violation is #[expect(lint, reason = "…")] — a suppression that states its case and (with unfulfilledlintexpectations = "deny", included) errors the day it stops being needed. Place it at the narrowest scope that contains the violation: a broad (module- or crate-wide) expectation is fulfilled as long as any occurrence exists, so it never expires and silently admits every future occurrence — an open-ended exception dressed as a finite one. When an entire scope genuinely is the unit of exception (an FFI crate and unsafecode, generated code, a configuration-dependent false positive), use an honest reasoned #![allow(lint, reason = "…")] instead. Outer #[allow] is a rejected pattern — allowattributes deliberately doesn't see inner attributes, and allowattributeswithout_reason still forces the reason on both.

Mode A: writing or reviewing Rust

  1. Read references/rules.md in full.
  2. While writing: follow it, plus whatever the mechanical config enforces if

installed. Match established repository idioms where the alternatives are semantically equivalent — consistency outranks this skill's stylistic and organizational preferences; it never outranks correctness, safety, error causality, lifecycle ownership, or explicit project invariants.

  1. While reviewing: order findings most severe first — fabricated evidence

(unsafe/Send/transmute misuse) > swallowed errors > panic-as-error-handling > lifecycle gaps (unowned tasks, unbounded queues) > borrow-checker appeasement > structure/abstraction. Every finding must state: the exact symbols involved; which evidence the code discards (validity, ownership, failure causality, lifecycle, safety, exhaustiveness); the concrete failure mode it enables — not "unidiomatic"; the smallest repair (prefer deleting or simplifying ownership over adding abstraction); how to prevent recurrence (a lint, a disallowed-* entry, a test); and what was inferred rather than proven. Raise no finding merely because a function is long, a clone or mutex or dyn exists, or a trait has one implementation — connect the smell to a failure, or drop it.

  1. Never "fix" a finding by erasing its evidence: no unreasoned suppression;

no error erasure unless erasure is the intentional, documented contract of that boundary; no clone whose sole purpose is ending an inconvenient borrow; no silent weakening of a behavioral assertion.

Mode B: installing the lint policy into a repository

  1. Inspect before changing: read the repo's agent instructions; check

git status and preserve unrelated changes; find the workspace root Cargo.toml, any existing clippy.toml/.clippy.toml, existing [lints]/[workspace.lints] tables, and #![allow(...)]/#![warn(...)] crate attributes that the table will supersede.

  1. Merge assets/workspace-lints.toml into the workspace root Cargo.toml.

Keep every existing lint entry; on conflict, keep the repo's stricter level and report the difference. In a single-crate repo without a workspace, use [lints.rust]/[lints.clippy] directly. Normalize priorities: this table is all named lints, but if the repo's existing table contains group entries (pedantic = "warn", nursery = …), those must sit at a lower priority than the named lints that override them — rewrite them as { level = "…", priority = -1 }, never rely on TOML entry order (same-priority group-vs-lint resolution is undefined; clippy::lintgroupspriority flags it). Preserve deliberate existing priorities and report any conflict.

  1. Opt members into the workspace table, case by case (skip in single-crate

repos). A member with no [lints] table gets [lints] workspace = true. A member with existing local lint entries CANNOT combine them with workspace = true — Cargo rejects that manifest; either migrate its entries into the workspace table (if they're general) or leave the crate on local lints and merge the anti-slop entries into them, reporting which. A special-profile crate (FFI, no_std, codegen) may stay opted out with a stated reason.

  1. Merge assets/clippy.toml into the repo's clippy.toml, preserving

existing disallowed-* entries and config keys.

  1. Propose architectural bans — often the highest-value step. From the repo's

own structure, identify APIs that should only be reachable through a project-owned seam (unbounded channels, raw tokio::spawn, wall clock, std::env, process::exit, raw fs access, println! in non-CLI crates) and activate the corresponding disallowed-methods templates in clippy.toml — but only where a real replacement already exists and owns actual policy (bounds, supervision, injection, context). Never ban an API whose "replacement" merely renames it; list the candidates without a replacement as recommendations instead.

  1. Validate against the repo's pinned toolchain: run

cargo clippy --workspace --all-targets and confirm no unknown lint / removed lint / config-parse warnings. Lint names drift across clippy versions; drop or rename entries that this toolchain rejects and report each one.

  1. If findings appear in existing code, report counts per lint. Fix them only

if the user asked for a cleanup; fix real causes, never launder (step 4 of Mode A). If the volume is large, propose demoting specific deny entries to warn as a migration step rather than sprinkling suppressions.

  1. For CI, recommend: cargo fmt --all --check, then

cargo clippy --workspace --all-targets over the repository's existing feature matrix (do not impose --all-features — projects with mutually exclusive features have their own combination strategy). Do NOT append -D warnings: it would promote the deliberately-advisory warn tier (and every default rustc/clippy warning) to failures, erasing the deny/warn distinction this policy encodes — the deny tier already fails the build on its own. A team that wants the warn tier enforced should promote specific lints to deny in the table, where the choice is explicit and versioned. Add cargo-deny and cargo-machete if supply-chain and dependency hygiene are wanted.

  1. Report: files changed, lints enabled at which levels, entries dropped for

toolchain compatibility, findings remaining.

Tuning expectations

The deny tier is meant to survive contact with real projects; the warn tier includes nursery lints (redundantclone, needlesscollect, significantdroptightening) that are known to have false positives and negatives — they are tripwires backing the prose rules, not the policy itself. indexingslicing and wildcardenummatcharm are the most contested entries: keep them for application code, expect pushback in parser/math-heavy crates, and demote there with a stated reason rather than repo-wide. This profile is deliberately orthogonal to style — it can coexist with or without clippy::pedantic; add pedantic separately if the team wants taste enforced, and never enable clippy::restriction as a group.

Toolchain floor: the full policy requires Rust 1.82+ ([lints] table 1.74+, #[expect]/reason 1.81+, unusedresultok 1.82+). Below that, run in compatibility mode: omit unsupported entries and substitute reasoned #[allow] where #[expect] is unavailable — and say so in the report, since the self-expiring suppression model is the part that changes.

Per-crate escalations, applied as guidance rather than shipped as separate profiles: public libraries add missingerrorsdoc = "warn", missingpanicsdoc = "warn" (failure modes are part of the contract) and keep avoid-breaking-exported-api = true; internal applications may set it to false in clippy.toml for full API-shape coverage. Safety-critical or no-panic crates escalate panic, indexingslicing, stringslice, and even expect_used to deny — a level that would be overkill as the default.

The last test for every rule, mechanical or prose: could following it cause an agent to replace a correct, explicit design with a more abstract or more complicated one solely to satisfy the wording? Where the answer is yes, the rule's job is to demand the design's argument — not to prescribe a syntax or an architecture.