Agent skill

Add Lint Rule

by jolars in jolars/panache

Add a new built-in lint rule to the Panache linter — wire it into the registry, gate it on the right extension/flavor, add a regression fixture with focused assertions, and document it.

MITAuto-check passedDevelopment

Install Add Lint Rule

skills CLI
$ npx skills add jolars/panache --skill add-lint-rule -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install jolars/panache add-lint-rule --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/jolars/panache.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/add-lint-rule .claude/skills/add-lint-rule && rm -rf skills-src

Use ~/.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/

Facts

Skill name
add-lint-rule
GitHub stars
238
Token cost
~2.8k tokens
SKILL.md length
1,274 words
Files
1
Skills in repo
10
Repo updated
First seen
Licence
MIT

At a glance

Add a new built-in lint rule to the Panache linter — wire it into the registry, gate it on the right extension/flavor, add a regression fixture with focused assertions, and document it.

  • Works in 7 steps: Pick the rule name (kebab-case) — this… → Decide gating before writing code —… → Write a failing test first (TDD per… → …
  • Tasks that involve Linting and formatting
  • SKILL.md covers Scope boundaries, Key files, Workflow and Dos and don'ts, plus 1 more section
  • Calls cargo

What it does

Add Lint Rule is an agent skill from jolars/panache. Add a new built-in lint rule to the Panache linter — wire it into the registry, gate it on the right extension/flavor, add a regression fixture with focused assertions, and document it.

Its SKILL.md is about 2.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Development, covering Linting and formatting. The repository describes itself as: Language server, formatter, and linter for Quarto and other Markdown flavors. The licence is MIT.

When your agent uses it

  • Tasks that involve Linting and formatting

Example prompts

  • “/add-lint-rule”

Workflow steps

7 steps, taken from the first numbered list in SKILL.md.

  1. Pick the rule name (kebab-case) — this is the diagnostic code, the
  2. Decide gating before writing code — these become fields on the rule's
  3. Write a failing test first (TDD per AGENTS.md). Either
  4. Implement the rule in src/linter/rules/.rs
  5. Wire it up (no if-guard — registration is data-driven from metadata())
  6. Document in docs/reference/linter-rules.qmd (enforced by
  7. Validate in this order

What it can do on your machine

Read from SKILL.md and the folder at commit 8f82e9a. It shows what the files ask for, not the result of running them.

  • Tool permissions

    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.

  • Runs code

    Shell commands in SKILL.md call:

    • cargo

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Add Lint Rule loads about 2.8k tokens when it runs. Until then it costs about 50 tokens; SKILL.md has 1,274 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~50
When it runs · the whole SKILL.md, loaded when a task matches
~2.8k

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.

Safety

Auto-check passed

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.

SKILL.md

The full file from jolars/panache at commit 8f82e9a, republished under its MIT licence (© jolars). 1,274 words, ~2,790 tokens.

Download SKILL.mdSave it as .claude/skills/add-lint-rule/SKILL.md (or your agent's skills folder).
name
add-lint-rule
description
Add a new built-in lint rule to the Panache linter — wire it into the registry, gate it on the right extension/flavor, add a regression fixture with focused assertions, and document it.

Use this skill when asked to add a new built-in lint rule (warning, error, or info), regardless of whether it ships with an auto-fix.

Scope boundaries

  • Built-in lint rules only. External-linter integrations (black, flake8, etc.) live in src/linter/external_linters* and are out of scope here.
  • Rule logic walks the parser CST/AST. Do not add parser- or formatter-side workarounds. If the rule needs information the CST does not expose, surface it through a typed wrapper in crates/panache-parser/src/syntax/ rather than re-parsing inside the rule.
  • LSP and CLI consume diagnostics through the same LintRunner. The rule must not emit CLI-formatted strings; it produces Diagnostic values and the shared rendering paths handle presentation.

Key files

  • src/linter/rules.rs — Rule trait (note the required metadata() method), the RuleMeta/DiagnosticCode/Requirement types, RuleRegistry, and the pub mod list. Every new rule module is declared here.
  • src/linter/rules/<rule_name>.rs — one file per rule. Contains the pub struct <Name>Rule plus its impl Rule (including metadata()) and unit tests.
  • src/linter.rs — all_rules() lists every rule once; default_registry() is data-driven: it filters all_rules() by each rule's RuleMeta::{requires, default_on} and config.lint. There is no per-rule if guard to add. builtin_rule_metadata() exposes the metadata for tests.
  • src/linter/diagnostics.rs — Diagnostic, Severity, Location, Edit, Fix, DiagnosticNoteKind. The full builder API for diagnostics.
  • src/syntax.rs — re-exports SyntaxKind, SyntaxNode, and typed AST wrappers from panache_parser::syntax.
  • tests/linting.rs + tests/linting/<rule_name>.{md,qmd,Rmd} — integration test fixtures. Pattern: a focused fixture file plus a #[test] that filters diagnostics by code and asserts count, span, and (if present) fix shape.
  • docs/reference/linter-rules.qmd — the per-rule catalogue. Every rule needs a ### \<rule-name>` {#<rule-name>}section.tests/linter_rules_docs.rscross-checks this file againstbuiltin_rule_metadata()` and fails the build if a rule, code, severity, auto-fix flag, default, or requirement drifts.
  • docs/guide/linting.qmd — user-facing prose guide; links to the reference and lists the default [lint.rules] keys. Update the example key list there too.

Workflow

  1. Pick the rule name (kebab-case) — this is the diagnostic code, the config key under [lint.rules], and the slug used in URLs/help text. It must be unique and stable: renaming it is a breaking config change. Match tone of existing names (heading-hierarchy, duplicate-reference-labels, adjacent-footnote-refs).

  2. Decide gating before writing code — these become fields on the rule's RuleMeta, the single source of truth for both registration and the docs:

    • Severity: Warning is the default; Error only for genuinely broken output; Info is reserved. A rule with several codes can mix severities; declare each in RuleMeta::codes.
    • requires: the Requirement variant the rule needs (Always, Footnotes, Citations, Emoji, FencedDivs, FencedCodeAttributes, HeaderAttributes, TexMath, or ChunkFlavor). Add a new variant (and its is_satisfied/doc-token mapping in tests/linter_rules_docs.rs) only if no existing one fits.
    • default_on: true for rules that run unless disabled; false for opt-in rules (registered only via is_rule_explicitly_enabled, documented with a Default: Off field).
    • Auto-fix: only ship a Fix when the replacement is unambiguous and preserves intent. If multiple resolutions are valid (rename vs delete vs merge), omit the fix and explain why in the docs. Set RuleMeta::auto_fix accordingly.
  3. Write a failing test first (TDD per AGENTS.md). Either:

    • a unit test inside the new module under #[cfg(test)] mod tests, using crate::parser::parse(input, Some(config.clone())) and calling Rule::check_tree(&tree, input, &config, metadata). check_tree is the default trait method that builds a one-off LintIndex for just this rule's declared interests and runs it — tests use it because Rule::check itself takes a &LintContext, which the runner (not tests) constructs. or
    • an integration fixture under tests/linting/<rule_name>.{md,qmd,Rmd} and a #[test] in tests/linting.rs that calls lint_file(...) and filters by d.code == "<rule-name>". Cover the positive case, the negative ("should not flag") case, and any edge case the rule explicitly handles.
  4. Implement the rule in src/linter/rules/<rule_name>.rs:

    • Rules do not walk the tree themselves. The runner does one shared tree.preorder_with_tokens() pass and buckets nodes by SyntaxKind; declare which kinds you want via node_interests() and read your bucket with cx.nodes(KIND) instead of tree.descendants(). This keeps a lint pass at one traversal no matter how many rules exist.
    • Cast bucket nodes to typed wrappers where available (cx.nodes(SyntaxKind::LINK).iter().cloned().filter_map(Link::cast)) — typed wrappers are preferred wherever they exist. For multi-kind rules, list every kind in node_interests() and iterate each bucket.
    • To scan TEXT tokens (e.g. byte-pattern checks), return true from wants_text_tokens() and iterate cx.text_tokens().
    • Salsa-index-backed rules (those that use symbol_usage_index_from_tree(.., cx.tree, ..) and never read a bucket) leave node_interests() at its empty default.
    • Build Location with Location::from_range(range, input) or Location::from_node(node, input).
    • For auto-fixes, prefer insertions (zero-width TextRange::new(p, p)) and replacements over a precise span rather than rewriting whole nodes. Multi-edit fixes are allowed but must be independent — they are applied in source order.
    • Honor the trait shape exactly. Implement metadata() (required), declare interests, then take a &LintContext (which bundles tree/input/config/metadata/index):
      rust
      fn metadata(&self) -> RuleMeta {
          RuleMeta {
              name: "<rule-name>",
              default_on: true,
              requires: Requirement::Always,
              auto_fix: false,
              codes: const { &[DiagnosticCode::warning("<rule-name>")] },
          }
      }
      
      fn node_interests(&self) -> &'static [SyntaxKind] {
          &[SyntaxKind::LINK] // omit (defaults to &[]) for index-backed rules
      }
      
      fn check(&self, cx: &LintContext) -> Vec<Diagnostic> {
          let input = cx.input; // also cx.tree / cx.config / cx.metadata as needed
          // ... iterate cx.nodes(SyntaxKind::LINK) ...
      }
      codes is &'static [DiagnosticCode]; wrap the array in a const { … } block (the ::warning/::error/::info const constructors are not rvalue-promotable on their own). Import the new types alongside the trait: use crate::linter::rules::{DiagnosticCode, LintContext, Requirement, Rule, RuleMeta};.
  5. Wire it up (no if-guard — registration is data-driven from metadata()):

    • Add pub mod <rule_name>; to src/linter/rules.rs (alphabetical, with the rest of the pub mod list).
    • Add one Box::new(rules::<rule_name>::<Name>Rule) entry to all_rules() in src/linter.rs. default_registry() filters that list by the rule's RuleMeta::{requires, default_on} and config.lint, so the gating you declared in step 2 takes effect automatically — there is nothing else to edit. (Opt-out via [lint.rules] is handled centrally for every rule.)
  6. Document in docs/reference/linter-rules.qmd (enforced by tests/linter_rules_docs.rs):

    • New ### \<rule-name>` {#<rule-name>}section under "Rules", placed near thematically related rules. Use the existing definition-list shape:Severity, Auto-fix, Requirements(ifrequiresis notAlways), optional Default(sayOffwhendefault_onisfalse), Diagnostic codes, Description, then an **Example violation:**block, and (if auto-fixable) an**Auto-fix output:**` block.
    • Every DiagnosticCode in the rule's metadata() must appear in the section, the Severity field must name each severity emitted, and the Requirements field must mention the gating token — otherwise the consistency test fails. Multi-code rules get a #### \<code>`` subsection per code.
    • If you reference the rule in the docs/guide/linting.qmd example [lint.rules] key list, keep that list in sync too (it is illustrative, not exhaustive, so this is optional).
  7. Validate in this order:

    • Targeted: cargo test --lib <rule_name>, cargo test --test linting <test_name>, and cargo test --test linter_rules_docs (catches docs/metadata drift).
    • CLI smoke check on a copy of the fixture: cargo run --quiet -- lint /tmp/<fixture>.md and cargo run --quiet -- lint --fix /tmp/<fixture>.md (verify the file contents after --fix).
    • Full: cargo check --workspace, cargo test --workspace, cargo clippy --workspace --all-targets --all-features -- -D warnings, cargo fmt -- --check.
Show full SKILL.md (189 more words)Show less

Dos and don'ts

  • Do keep diagnostic spans tight (point at the offending construct, not the whole line/paragraph) — this drives both the CLI caret and LSP underlines.
  • Do put rule logic in the rule module. Shared cross-rule helpers belong in src/linter/ (e.g. via crate::salsa::symbol_usage_index_from_tree), not duplicated.
  • Do respect ignore directives implicitly — LintRunner::run_with_metadata already filters by ignored ranges, so the rule emits unconditionally.
  • Don't emit CLI strings, ANSI codes, or eprintln! from a rule. Return Diagnostic values and let the renderer handle output.
  • Don't rely on lexically scanning input. Walk the CST/AST.
  • Don't add a fix that changes prose semantics. If the user's intent is ambiguous, omit the fix.
  • Don't rename an existing rule code to fix a typo without a migration plan — the code is part of the user-facing config surface.

Report-back format

When done, report:

  1. Rule name (code), severity, and whether it ships an auto-fix.
  2. The Requirement and default_on it declares in RuleMeta.
  3. New files (rule module, fixture) and updated files (rules.rs, linter.rs all_rules(), linting.rs, linter-rules.qmd).
  4. Targeted test names (including linter_rules_docs) and CLI fix smoke-test outcome.
  5. Full-suite validation results (cargo test --workspace, clippy, fmt).

© jolars, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/add-lint-rule of jolars/panache.

Open the folder on GitHubat commit 8f82e9a

Compare with similar skills

Add Lint 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.

Add Lint Rule compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Add Lint Rule this skilljolars/panache238—~2.8kAutomated safety check: PassMIT
Minimizing Ty Ecosystem Changesastral-sh/ruff50k—~4.6kAutomated safety check: PassMIT
Install Anti-Slop Oxlint Rulesdmmulroy/anti-slop5.4k—~2.2kAutomated safety check: PassMIT
Babysit PR To Pass CIsgl-project/sglang37k2 repos~3kAutomated safety check: PassApache-2.0
Rust Best Practicesfarm-fe/farm5.6k3 repos~1.1kAutomated safety check: PassMIT
Summarise Ecosystem Resultsastral-sh/ruff50k—~2.2kAutomated safety check: PassMIT

Similar skills

  • Official

    A skill your agent uses when a user says "minimize this ty ecosystem change", "reproduce this ecosystem result", "investigate a primer difference", "investigate a mypyprimer difference"…

    50k GitHub stars~4.6k tokensUpdated today
    DevelopmentAuto-check passed
  • Installs, updates or migrates the vendored anti-slop Oxlint plugin in a repository, keeping local rule changes and the plugin's license and provenance files.

    5.4k GitHub stars~2.2k tokensUpdated 1 mo ago
    DevelopmentAuto-check passed
  • Babysit PR To Pass CI

    sgl-project/sglang

    Start and persistently pursue a goal to babysit an SGLang pull request until selected GitHub Actions workflows pass on the latest PR head.

    37k GitHub starsUsed in 2 repos~3k tokens
    DevelopmentAuto-check passed
  • Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook.

    5.6k GitHub starsUsed in 3 repos~1.1k tokens
    DevelopmentAuto-check passed
  • Official

    A skill your agent uses when a user says "summarise ecosystem results", "summarize this ty ecosystem report", "what changed in this ecosystem run?", or asks to summarise or summarize ty ecosystem…

    50k GitHub stars~2.2k tokensUpdated today
    DevelopmentAuto-check passed
  • Go Pedantry

    chromedp/chromedp

    This skill should be used when the user is writing Go code and needs guidance on Go-specific pedantry: error wrapping with fmt.Errorf and %w, interface design (accept interfaces return structs)…

    13k GitHub stars~3.7k tokensUpdated today
    DevelopmentAuto-check passed

More from jolars/panache

All 10 skills in this repo
  • Add Syntax Construct

    jolars/panache

    Add a new block-level or inline-level syntax construct to Panache's parser and formatter — confirm the pandoc-native shape first, add SyntaxKinds for every byte category, gate it behind an extension…

    238 GitHub stars~1.8k tokensUpdated today
    Auto-check passed
  • Grow Panache's CommonMark spec conformance under Flavor::CommonMark by running every spec.txt example through the shared parser, comparing rendered HTML against the spec's expected HTML…

    238 GitHub stars~1.1k tokensUpdated today
    Auto-check passed
  • External Tools

    jolars/panache

    Work on Panache's delegation of embedded code blocks to third-party formatters and linters (ruff, shfmt, shellcheck, rustfmt, ...) — add or change a preset, fix the offset mapping that translates a…

    238 GitHub stars~1.2k tokensUpdated today
    Auto-check passed
  • Linter Investigation

    jolars/panache

    Investigate panache's linter (and, secondarily, its parser) against a real-world Quarto/Markdown codebase.

    238 GitHub stars~2k tokensUpdated today
    Auto-check passed
  • Math Parser Formatter

    jolars/panache

    Implement or debug Panache's TeX math parser and formatter internals, including the lossless CST, semantic model, diagnostics, and Badness parity.

    238 GitHub stars~1.5k tokensUpdated today
    Auto-check passed
  • Perf Investigation

    jolars/panache

    Profile-driven performance work on the panache parser or formatter.

    238 GitHub stars~3.3k tokensUpdated today
    Auto-check passed

Categories

Questions about Add Lint Rule

What does Add Lint Rule do?

Add a new built-in lint rule to the Panache linter — wire it into the registry, gate it on the right extension/flavor, add a regression fixture with focused assertions, and document it. Add Lint Rule is an agent skill from jolars/panache. Add a new built-in lint rule to the Panache linter — wire it into the registry, gate it on the right extension/flavor, add a regression fixture with focused assertions, and document it.

When should I use Add Lint Rule?

Add Lint Rule fits situations like: tasks that involve Linting and formatting.

How do I install Add Lint Rule in Claude Code?

Run `npx skills add jolars/panache --skill add-lint-rule -a claude-code`. Or copy the skill folder (.agents/skills/add-lint-rule in jolars/panache) into .claude/skills/add-lint-rule in your project. Claude Code loads it when a task matches its description.

How do I install Add Lint Rule in Codex?

Run `npx skills add jolars/panache --skill add-lint-rule -a codex`. Or copy the skill folder (.agents/skills/add-lint-rule in jolars/panache) into .agents/skills/add-lint-rule in your project. Codex loads it when a task matches its description.

Can I use Add Lint Rule in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add jolars/panache --skill add-lint-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/add-lint-rule, .gemini/skills/add-lint-rule, .github/skills/add-lint-rule and .opencode/skills/add-lint-rule in your project.

What does Add Lint Rule need to run?

Going by SKILL.md and its folder, Add Lint Rule needs the command-line tools its instructions call (cargo).

Does Add Lint Rule access the network?

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.

Is Add Lint Rule safe to install?

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.

What licence does Add Lint Rule use?

Add Lint Rule is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Add Lint Rule use?

About 2.8k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Add Lint Rule?

Skills that share tags, products or a category with Add Lint Rule: Minimizing Ty Ecosystem Changes (astral-sh/ruff, 50k stars), Install Anti-Slop Oxlint Rules (dmmulroy/anti-slop, 5.4k stars), Babysit PR To Pass CI (sgl-project/sglang, 37k stars) and Rust Best Practices (farm-fe/farm, 5.6k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Add Lint Rule?

jolars (a GitHub user) maintains it in jolars/panache, which has 238 GitHub stars. The repository holds 10 skills in this directory. The repository was last updated on October 10, 2026.

Source: jolars/panache on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.