Rust Best Practices
farm-fe/farm
Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook.
Implement a shuck-rs lint rule from its YAML definition in docs/rules/.
$ npx skills add ewhauser/shuck --skill implement-rule -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install ewhauser/shuck implement-rule --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/ewhauser/shuck.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/implement-rule .claude/skills/implement-rule && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "implement-rule" agent skill from https://github.com/ewhauser/shuck/tree/main/.claude/skills/implement-rule into .claude/skills/implement-rule/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "implement-rule", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/ewhauser/shuck/tree/main/.claude/skills/implement-ruleType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add ewhauser/shuck --skill implement-rule -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install ewhauser/shuck implement-rule --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ewhauser/shuck.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/implement-rule .agents/skills/implement-rule && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "implement-rule" agent skill from https://github.com/ewhauser/shuck/tree/main/.claude/skills/implement-rule into .agents/skills/implement-rule/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "implement-rule", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ewhauser/shuck --skill implement-rule -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install ewhauser/shuck implement-rule --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ewhauser/shuck.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/implement-rule .cursor/skills/implement-rule && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "implement-rule" agent skill from https://github.com/ewhauser/shuck/tree/main/.claude/skills/implement-rule into .cursor/skills/implement-rule/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "implement-rule", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/ewhauser/shuck.git --path .claude/skills/implement-rule--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add ewhauser/shuck --skill implement-rule -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install ewhauser/shuck implement-rule --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ewhauser/shuck.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/implement-rule .gemini/skills/implement-rule && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "implement-rule" agent skill from https://github.com/ewhauser/shuck/tree/main/.claude/skills/implement-rule into .gemini/skills/implement-rule/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "implement-rule", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install ewhauser/shuck implement-ruleInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add ewhauser/shuck --skill implement-rule -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/ewhauser/shuck.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/implement-rule .github/skills/implement-rule && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "implement-rule" agent skill from https://github.com/ewhauser/shuck/tree/main/.claude/skills/implement-rule into .github/skills/implement-rule/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "implement-rule", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ewhauser/shuck --skill implement-rule -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install ewhauser/shuck implement-rule --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ewhauser/shuck.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/implement-rule .opencode/skills/implement-rule && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "implement-rule" agent skill from https://github.com/ewhauser/shuck/tree/main/.claude/skills/implement-rule into .opencode/skills/implement-rule/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "implement-rule", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
implement-ruleImplement a shuck-rs lint rule from its YAML definition in docs/rules/.
Implement Rule is an agent skill from ewhauser/shuck. Implement a shuck-rs lint rule from its YAML definition in docs/rules/. Use this skill whenever the user asks to implement a rule (e.g., "implement C003", "implement docs/rules/X001.yaml", "add the unused-assignment rule"), wire up a new lint check, or build out a rule from its definition. This is about writing the Rust code that makes a rule actually detect violations — not about importing rule definitions (that's the import-rules skill).
Its SKILL.md is about 4.8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files (for example `evals/evals.json`).
It sits in Development, covering Linting and formatting. It works with Rust. The repository describes itself as: A lightning fast shell linter/formatter/LSP server with zsh support. The licence is MIT.
8 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 904974e. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
cargoFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Implement Rule loads about 4.8k tokens when it runs. Until then it costs about 115 tokens; SKILL.md has 1,214 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from ewhauser/shuck at commit 904974e, republished under its MIT licence (© ewhauser). 1,214 words, ~4,771 tokens.
.claude/skills/implement-rule/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.This skill turns a YAML rule definition in docs/rules/ into a working lint rule with
violation struct, checker dispatch, test fixture, and snapshot test.
Read these files to understand the current state:
docs/rules/C003.yaml)crates/shuck-linter/src/registry.rs — to see existing rules and find where to insertcrates/shuck-linter/src/checker.rs — to see current dispatch phasescrates/shuck-linter/src/rules/correctness/unused_assignment.rs — the reference implementation to followAlso read the semantic model to understand what data is available for the rule:
crates/shuck-semantic/src/lib.rs — SemanticModel public APIRead the YAML definition. Key fields:
new_category: Correctness # → Category module: correctness, style, performance, portability, security
new_code: C001 # → Rule code used in registry
shellcheck_code: SC2034 # → ShellCheck mapping for suppression
description: ... # → What the rule detects
examples: # → Test cases to base the fixture onFrom the description and examples, determine:
File: crates/shuck-linter/src/registry.rs
Add an entry to the declare_rules! macro. Choose a PascalCase variant name that clearly describes the violation. Insert it in code-order (C001 before C002, etc.).
declare_rules! {
("C001", Category::Correctness, Severity::Warning, UnusedAssignment),
// Add new rule here in code-sorted order
("C003", Category::Correctness, Severity::Warning, NewRuleName),
...
}Severity guidelines:
Error — the code is almost certainly wrong (undefined variable, unreachable code)Warning — likely a problem but could be intentional (unused assignment, unquoted expansion)Hint — suggestion, no real risk (style preferences)If the YAML has a legacy_code (SH-NNN), add a legacy alias in code_to_rule():
"SH-NNN" => Some(Rule::NewRuleName),If there's a shellcheck_code, add it to crates/shuck-linter/src/suppression/shellcheck_map.rs:
(NNNN, Rule::NewRuleName), // SCNNNNIf this is the first rule in a category, create the module structure:
crates/shuck-linter/src/rules/{category}/
├── mod.rsAnd register it in crates/shuck-linter/src/rules/mod.rs:
pub mod correctness;
pub mod style; // new categoryThe mod.rs should contain a #[cfg(test)] block following the snapshot test pattern:
#[cfg(test)]
mod tests {
use std::path::Path;
use test_case::test_case;
use crate::{LinterSettings, Rule, assert_diagnostics};
use crate::test::test_path;
#[test_case(Rule::NewRuleName, Path::new("C003.sh"))]
fn rules(rule: Rule, path: &Path) -> anyhow::Result<()> {
let snapshot = format!("{}_{}", rule.code(), path.display());
let (diagnostics, source) = test_path(
Path::new("{category}").join(path).as_path(),
&LinterSettings::for_rule(rule),
)?;
assert_diagnostics!(snapshot, diagnostics, &source);
Ok(())
}
}If the category module already exists, just add a new #[test_case] line to the existing rules function.
Create crates/shuck-linter/src/rules/{category}/{rule_name}.rs.
Critical design principle: Rules must be cheap filters over pre-computed facts. Do NOT add
direct AST walks, traversal helpers, command normalization, test operand reconstruction, or
word/redirect/substitution classification in rule files. If a rule needs new structural data,
add it to LinterFacts in crates/shuck-linter/src/facts.rs and consume it from there.
Rules access data through two paths:
checker.facts() — Pre-computed LinterFacts. This is the primary data source for most
rules. Facts normalize commands, extract options, classify words, analyze tests, and index
structural patterns (pipelines, loops, redirects, substitutions). Prefer facts for anything
structural or command-oriented.
checker.semantic() — The SemanticModel. Use this for variable binding/reference
analysis (unused assignments, undefined variables, scope queries, call graphs). These rules
iterate semantic collections directly.
use crate::{Checker, Rule, Violation};
pub struct RuleName {
// Fields that provide context for the diagnostic message.
// Common: `name: String` for variable names.
// Use no fields if the message is always the same (preferred).
}
impl Violation for RuleName {
fn rule() -> Rule {
Rule::RuleName
}
fn message(&self) -> String {
// Concise, lowercase message describing the violation.
"description of what's wrong".to_owned()
}
}Register the module in the category's mod.rs:
pub mod rule_name;Filter pre-computed facts, collect spans, report. This is the standard pattern.
Command facts — for rules about specific commands (read, printf, exit, find, xargs, sudo, etc.):
pub fn read_without_raw(checker: &mut Checker) {
let spans = checker
.facts()
.structural_commands() // iterator over CommandFact
.filter(|fact| fact.effective_name_is("read")) // normalized name (unwraps env/command/sudo)
.filter(|fact| {
fact.options()
.read() // pre-parsed ReadCommandFacts
.is_some_and(|read| !read.uses_raw_input)
})
.filter_map(|fact| fact.body_name_word().map(|word| word.span))
.collect::<Vec<_>>();
checker.report_all(spans, || ReadWithoutRaw);
}Pipeline facts — for rules about piped command sequences:
pub fn find_output_to_xargs(checker: &mut Checker) {
let spans = checker
.facts()
.pipelines() // &[PipelineFact]
.iter()
.flat_map(|pipeline| unsafe_find_to_xargs_spans(checker, pipeline))
.collect::<Vec<_>>();
checker.report_all_dedup(spans, || FindOutputToXargs);
}
fn unsafe_find_to_xargs_spans(checker: &Checker<'_>, pipeline: &PipelineFact<'_>) -> Vec<Span> {
pipeline.segments().windows(2).filter_map(|pair| {
let left = checker.facts().command_for_stmt(pair[0].stmt())?; // cross-reference
let right = checker.facts().command_for_stmt(pair[1].stmt())?;
if !pair[0].effective_name_is("find") || !pair[1].effective_name_is("xargs") {
return None;
}
if left.options().find().is_some_and(|f| f.has_print0)
&& right.options().xargs().is_some_and(|x| x.uses_null_input) {
return None; // null-delimited pair is safe
}
Some(left.body_span())
}).collect()
}Loop header facts — for rules about for/select loop iteration lists:
pub fn find_output_loop(checker: &mut Checker) {
let spans = checker
.facts()
.for_headers() // &[ForHeaderFact]
.iter()
.flat_map(|header| header.words().iter())
.filter(|word| word.contains_find_substitution()) // pre-computed
.map(|word| word.span())
.collect::<Vec<_>>();
checker.report_all(spans, || FindOutputLoop);
}Test/conditional facts — for rules about [...] and [[...]] tests:
pub fn constant_comparison_test(checker: &mut Checker) {
let spans = checker
.facts()
.commands()
.iter()
.filter(|fact| {
fact.simple_test().is_some_and(simple_test_is_constant) // SimpleTestFact
|| fact.conditional().is_some_and(conditional_is_constant) // ConditionalFact
})
.map(|fact| fact.span())
.collect::<Vec<_>>();
checker.report_all(spans, || ConstantComparisonTest);
}Redirect facts — for rules about redirections on specific commands:
pub fn sudo_redirection_order(checker: &mut Checker) {
let spans = checker
.facts()
.commands()
.iter()
.filter(|fact| fact.has_wrapper(WrapperKind::SudoFamily))
.flat_map(|fact| {
fact.redirect_facts().iter().filter_map(|redirect| {
(redirects_output(redirect.redirect().kind)
&& !redirect.analysis()
.is_some_and(|a| a.is_definitely_dev_null()))
.then(|| redirect.target_span()).flatten()
})
})
.collect::<Vec<_>>();
checker.report_all_dedup(spans, || SudoRedirectionOrder);
}Surface fragment facts — for lexer-level patterns (backticks, single quotes, etc.):
// Access via checker.facts().backtick_fragments(), .single_quoted_fragments(), etc.Word facts — for rules about word expansion contexts:
// Access via checker.facts().word_facts(), .expansion_word_facts(context), .case_subject_facts()| Method | Returns | Use for |
|---|---|---|
facts.commands() | All command facts | General command matching |
facts.structural_commands() | Top-level commands (iterator) | Commands not inside substitutions |
facts.pipelines() | Pipeline facts | Multi-command pipe analysis |
facts.for_headers() / facts.select_headers() | Loop list facts | Loop iteration patterns |
facts.lists() | List operator facts | Mixed &&/|| detection |
facts.word_facts() | Word expansion facts | Quoting/expansion analysis |
facts.expansion_word_facts(ctx) | Words in specific context | Context-filtered word analysis |
facts.case_subject_facts() | Case subject word facts | Case statement analysis |
facts.single_quoted_fragments() | Single-quoted spans | Literal-in-quotes detection |
facts.backtick_fragments() | Backtick substitution spans | Legacy syntax detection |
facts.command_for_stmt(stmt) | Command fact by AST node | Cross-referencing pipelines/loops |
facts.command_for_command(cmd) | Command fact by Command | Lookup from AST reference |
facts.word_fact(span, ctx) | Word fact by span+context | Targeted word lookup |
| Method | Returns | Use for |
|---|---|---|
fact.effective_name_is(name) | bool | Normalized name check (unwraps wrappers) |
fact.has_wrapper(kind) | bool | Check for sudo/env/command wrapping |
fact.options() | CommandOptionFacts | Pre-parsed command-specific options |
fact.body_name_word() | Option<&Word> | The body command's name word (for span) |
fact.body_span() | Span | Span of the body command |
fact.span() | Span | Full command span |
fact.redirect_facts() | &[RedirectFact] | Pre-analyzed redirections |
fact.simple_test() | Option<&SimpleTestFact> | [...] test structure |
fact.conditional() | Option<&ConditionalFact> | [[...]] test structure |
fact.substitution_facts() | &[SubstitutionFact] | Command substitution metadata |
| Method | Returns | Use for |
|---|---|---|
.read() | Option<ReadCommandFacts> | read -r detection |
.printf() | Option<PrintfCommandFacts> | Format word extraction |
.unset() | Option<UnsetCommandFacts> | Function mode, operand words |
.find() | Option<FindCommandFacts> | -print0 detection |
.xargs() | Option<XargsCommandFacts> | -0/--null detection |
.exit() | Option<ExitCommandFacts> | Status word and staticness |
.sudo_family() | Option<SudoFamilyCommandFacts> | Invoker type (sudo/doas/run0) |
For rules that analyze variable assignments and references, iterate semantic collections directly:
pub fn unused_assignment(checker: &mut Checker) {
for &binding_id in checker.semantic().unused_assignments() {
let binding = checker.semantic().binding(binding_id);
if !is_reportable(binding.kind, binding.attributes) { continue; }
if binding.attributes.contains(BindingAttributes::EXPORTED) { continue; }
if matches!(binding.kind, BindingKind::Nameref) { continue; }
checker.report(
UnusedAssignment { name: binding.name.to_string() },
binding.span,
);
}
}| Method | Returns | Use for |
|---|---|---|
semantic.bindings() | All variable bindings | Iterating assignments |
semantic.binding(id) | Single binding | Looking up by ID |
semantic.references() | All variable references | Iterating uses |
semantic.resolved_binding(ref_id) | Binding a reference resolves to | Def-use chains |
semantic.unresolved_references() | References with no binding | Undefined variables |
semantic.unused_assignments() | Bindings never read | Dead assignments |
semantic.declarations() | declare/local/export commands | Declaration analysis |
semantic.source_refs() | source/. commands | Dynamic source paths |
semantic.call_sites_for(name) | Where a function is called | Function call analysis |
semantic.call_graph() | Reachable/uncalled functions | Dead function detection |
semantic.scope_kind(id) | File/Function/Subshell/Pipeline | Scope-aware rules |
// Skip exported variables (consumed by child processes)
if binding.attributes.contains(BindingAttributes::EXPORTED) { continue; }
// Skip function definitions (not regular assignments)
if matches!(binding.kind, BindingKind::FunctionDefinition) { continue; }
// Skip nameref bindings (used indirectly)
if matches!(binding.kind, BindingKind::Nameref) { continue; }
// Skip imported bindings
if matches!(binding.kind, BindingKind::Imported) { continue; }walk_commands, iter_commands, or
recurse through child nodes. If you need structural data, add it to LinterFacts.fact.effective_name_is() and
fact.has_wrapper() — names are already normalized through env/command/sudo wrappers.fact.options().read(), .find(), .xargs(), etc.
If a new command needs option analysis, add it to CommandOptionFacts in facts.rs.WordFact with its expansion
analysis, operand class, and static text. Add new word analysis to facts.rs if needed.SimpleTestFact and ConditionalFact with their
pre-computed shapes, operator families, and operand classes.crate::rules::common::* in rule files. Rule-facing shared types come
from the crate root (re-exported from common modules).File: crates/shuck-linter/src/checker.rs
Add the rule invocation to the appropriate phase method:
fn check_command_facts(&mut self) {
// ... existing rules ...
if self.is_rule_enabled(Rule::NewRuleName) {
rules::category::rule_name::rule_name(self);
}
}Match the rule to the phase based on what data it primarily consumes:
| Phase | Use when the rule... | Examples |
|---|---|---|
check_bindings | Iterates semantic bindings (assignments) | UnusedAssignment |
check_references | Iterates semantic references (variable uses) | UndefinedVariable |
check_scopes | Checks scope-level properties | (reserved) |
check_declarations | Checks declare/local/export | LocalTopLevel |
check_call_sites | Checks function call patterns | OverwrittenFunction |
check_source_refs | Checks source/. commands | DynamicSourcePath |
check_command_facts | Filters command facts (name, options, structure) | ReadWithoutRaw, InvalidExitStatus, PrintfFormatVariable |
check_word_and_expansion_facts | Filters word/expansion facts | UnquotedExpansion, TrapStringExpansion, CasePatternVar |
check_loop_list_and_pipeline_facts | Filters pipeline/loop/list facts | FindOutputToXargs, FindOutputLoop, LoopFromCommandOutput |
check_redirect_and_substitution_facts | Filters redirect/substitution facts | SudoRedirectionOrder, SubstWithRedirect |
check_surface_fragment_facts | Filters lexer-level fragment facts | LegacyBackticks, SingleQuotedLiteral |
check_test_and_conditional_facts | Filters test/conditional facts | ConstantComparisonTest, QuotedBashRegex |
check_flow | Needs CFG/dataflow analysis | UnreachableAfterExit |
Decision guide: If the rule iterates checker.semantic().*, use one of the first six
phases. If it iterates checker.facts().*, pick the fact-category phase that matches.
Most new rules will use one of the fact-based phases (check_command_facts through
check_test_and_conditional_facts).
File: crates/shuck-linter/resources/test/fixtures/{category}/{CODE}.sh
Write a shell script that exercises both positive cases (should trigger) and negative cases (should not trigger). Use comments to label each section:
#!/bin/sh
# Should trigger: description of case
problematic_code_here
# Should not trigger: description of case
valid_code_hereCover:
cargo test -p shuck-linterThe snapshot test will fail the first time (new snapshot). Review the output to confirm it looks correct, then accept:
cargo insta accept --workspaceRun the full test suite to check for regressions:
cargo test --workspaceAfter implementation, report:
© ewhauser, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in .claude/skills/implement-rule of ewhauser/shuck.
Open the folder on GitHubat commit 904974e
Implement Rule next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Implement Rule this skillewhauser/shuck | 137 | — | ~4.8k | Automated safety check: Pass | MIT | |
| Rust Best Practicesfarm-fe/farm | 5.6k | 3 repos | ~1.1k | Automated safety check: Pass | MIT | |
| Doc Commentsbiomejs/biome | 26k | — | ~3k | Automated safety check: Pass | Apache-2.0 | |
| Rust Hygiene Audittsz-org/tsz | 577 | — | ~1.5k | Automated safety check: Pass | Apache-2.0 | |
| Releasexin2017338/lynx-proxy | 502 | — | ~1.1k | Automated safety check: Pass | MIT | |
| Flowmark Markdown Formatterjlevy/repren | 374 | — | ~631 | Automated safety check: Pass | MIT |
farm-fe/farm
Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook.
biomejs/biome
A skill your agent uses whenever writing or editing Rust //, ///, or //!
tsz-org/tsz
Run a deep DRY + code-hygiene audit of the Rust workspace and turn the findings into verified, deduplicated, hierarchical GitHub tech-debt issues.
xin2017338/lynx-proxy
Publish a new release version of Lynx Proxy. An agent skill from xin2017338/lynx-proxy.
jlevy/repren
Formats Markdown with the Flowmark auto-formatter for typographic cleanup and semantic line breaks, and helps adopt it across a repository.
timescale/rsigma
Use the rsigma CLI and MCP server: engine eval, engine daemon, rule lint, rule draft, rule tune, rule backtest, backend convert, mcp serve.
ewhauser/shuck
Profile shuck scripts and large-corpus fixtures, especially requests to profile a corpus script/fixture, reprofile after a shuck performance change, or produce a hotspot table from a samply profile.
ewhauser/shuck
Compare benchmark performance between two git worktrees (or the current worktree vs main).
ewhauser/shuck
Verify ShellCheck conformance for a shuck rule by running the large corpus test, analyzing deltas, and producing a structured bug document in docs/bugs/.
ewhauser/shuck
Fix a shuck lint rule that has conformance deltas against ShellCheck.
ewhauser/shuck
Implement an autofix for an existing shuck-rs lint rule. An agent skill from ewhauser/shuck.
ewhauser/shuck
Write and update technical design specifications. An agent skill from ewhauser/shuck.
Works with
Categories
Implement a shuck-rs lint rule from its YAML definition in docs/rules/. Implement Rule is an agent skill from ewhauser/shuck. Implement a shuck-rs lint rule from its YAML definition in docs/rules/.
Implement Rule fits situations like: the user asks to implement a rule (e.g; implement docs/rules/X001.yaml; add the unused-assignment rule); wire up a new lint check.
Run `npx skills add ewhauser/shuck --skill implement-rule -a claude-code`. Or copy the skill folder (.claude/skills/implement-rule in ewhauser/shuck) into .claude/skills/implement-rule in your project. Claude Code loads it when a task matches its description.
Run `npx skills add ewhauser/shuck --skill implement-rule -a codex`. Or copy the skill folder (.claude/skills/implement-rule in ewhauser/shuck) into .agents/skills/implement-rule in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ewhauser/shuck --skill implement-rule -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/implement-rule, .gemini/skills/implement-rule, .github/skills/implement-rule and .opencode/skills/implement-rule in your project.
Going by SKILL.md and its folder, Implement Rule needs the command-line tools its instructions call (cargo).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Implement Rule is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.8k tokens (SKILL.md is roughly 19k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Implement Rule: Rust Best Practices (farm-fe/farm, 5.6k stars), Doc Comments (biomejs/biome, 26k stars), Rust Hygiene Audit (tsz-org/tsz, 577 stars) and Release (xin2017338/lynx-proxy, 502 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
ewhauser (a GitHub user) maintains it in ewhauser/shuck, which has 137 GitHub stars. The repository holds 8 skills in this directory. The repository was last updated on October 5, 2026.
Source: ewhauser/shuck on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.