Skip to content
Development
Skill

/diagnostics-development

Guide for creating high-quality, user-friendly diagnostics in Biome. Use when creating diagnostics for lint rules, adding helpful advice to error messages, implementing code frame displays, or improving diagnostic quality.

From plugin
biome
26k12 skills
Install
$ npx -y skills add biomejs/biome --skill diagnostics-development --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/diagnostics-development

Context preview

The summary Claude sees to decide when to auto-load this skill.

Guide for creating high-quality, user-friendly diagnostics in Biome. Use when creating diagnostics for lint rules, adding helpful advice to error messages, implementing code frame displays, or improving diagnostic quality.

SKILL.md

diagnostics-development.SKILL.md
name: diagnostics-development
description: Guide for creating high-quality, user-friendly diagnostics in Biome. Use when creating diagnostics for lint rules, adding helpful advice to error messages, implementing code frame displays, or improving diagnostic quality.
compatibility: Designed for coding agents working on the Biome codebase (github.com/biomejs/biome).

Purpose

Use this skill when creating diagnostics - the error messages, warnings, and hints shown to users. Covers the `Diagnostic` trait, advice types, and best practices for clear, actionable messages.

Prerequisites

1. Read `crates/biome_diagnostics/CONTRIBUTING.md` for concepts 2. Understand Biome's [Technical Principles](https://biomejs.dev/internals/philosophy/#technical) 3. Follow the "show don't tell" philosophy

Diagnostic Principles

1. **Explain what** - State what the error is (diagnostic message) 2. **Explain why** - Explain why it's an error (advice notes) 3. **Tell how to fix** - Provide actionable fixes (code actions, diff advice, command advice)

**Follow Technical Principles:**

  • Informative: Explain, don't just state
  • Concise: Short messages, rich context via advices
  • Actionable: Always suggest how to fix
  • Show don't tell: Prefer code frames over textual explanations

Common Workflows

Create a Diagnostic Type

Use the `#[derive(Diagnostic)]` macro:

use biome_diagnostics::{Diagnostic, category};

#[derive(Debug, Diagnostic)]
#[diagnostic(
    severity = Error,
    category = "lint/correctness/noVar"
)]
struct NoVarDiagnostic {
    #[location(span)]
    span: TextRange,

    #[message]
    #[description]
    message: MessageAndDescription,

    #[advice]
    advice: NoVarAdvice,
}

#[derive(Debug)]
struct MessageAndDescription;

impl fmt::Display for MessageAndDescription {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Use 'let' or 'const' instead of 'var'")
    }
}

Implement Advices

Create advice types that implement `Advices` trait:

use biome_diagnostics::{Advices, Visit};
use biome_console::markup;

struct NoVarAdvice {
    is_const_candidate: bool,
}

impl Advices for NoVarAdvice {
    fn record(&self, visitor: &mut dyn Visit) -> std::io::Result<()> {
        if self.is_const_candidate {
            visitor.record_log(
                LogCategory::Info,
                &markup! {
                    "This variable is never reassigned, use 'const' instead."
                }
            )?;
        } else {
            visitor.record_log(
                LogCategory::Info,
                &markup! {
                    "Variables declared with 'var' are function-scoped, use 'let' for block-scoping."
                }
            )?;
        }
        Ok(())
    }
}

Use Built-in Advice Types

use biome_diagnostics::{LogAdvice, CodeFrameAdvice, DiffAdvice, CommandAdvice, LogCategory};

// Log advice - simple text message
LogAdvice {
    category: LogCategory::Info,
    text: markup! { "Consider using arrow functions." },
}

// Code frame advice - highlight code location
// Fields: path (AsResource), span (AsSpan), source_code (AsSourceCode)
CodeFrameAdvice {
    path: "file.js",
    span: node.text_range(),
    source_code: ctx.source_code(),
}

// Diff advice - show a TextEdit diff
DiffAdvice {
    diff: text_edit,  // must implement AsRef<TextEdit>
}

// Command advice - suggest CLI command
CommandAdvice {
    command: "biome check --write",
}

In practice, most lint rules use the `RuleDiagnostic` builder pattern instead of constructing advice types directly. See the [Add Diagnostic to Rule](#add-diagnostic-to-rule) section below.

Add Diagnostic to Rule

use biome_analyze::{Rule, RuleDiagnostic};

impl Rule for NoVar {
    fn diagnostic(ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
        let node = ctx.query();

        Some(
            RuleDiagnostic::new(
                rule_category!(),
                node.range(),
                markup! {
                    "Using "<Emphasis>"var"</Emphasis>" is not recommended."
                },
            )
            .note(markup! {
                "Variables declared with "<Emphasis>"var"</Emphasis>" are function-scoped, not block-scoped, which means they can leak outside of loops and conditionals and cause unexpected behavior."
            })
            .note(markup! {
                "Consider using "<Emphasis>"let"</Emphasis>" or "<Emphasis>"const"</Emphasis>" instead."
            })
        )
    }
}

Use Markup for Rich Text

Biome supports rich markup in diagnostic messages:

use biome_console::markup;

markup! {
    // Emphasis (bold/colored)
    "Use "<Emphasis>"const"</Emphasis>" instead."

    // Code/identifiers
    "The variable "<Emphasis>{variable_name}</Emphasis>" is never used."

    // Hyperlinks
    "See the "<Hyperlink href="https://example.com">"documentation"</Hyperlink>"."

    // Interpolation
    "Found "{count}" issues."
}

Register Diagnostic Category

Add new categories to `crates/biome_diagnostics_categories/src/categories.rs`:

define_categories! {
    // Existing categories...

    "lint/correctness/noVar": "https://biomejs.dev/linter/rules/no-var",
    "lint/style/useConst": "https://biomejs.dev/linter/rules/use-const",
}

Create Multi-Advice Diagnostics

#[derive(Debug, Diagnostic)]
#[diagnostic(severity = Warning)]
struct ComplexDiagnostic {
    #[location(span)]
    span: TextRange,

    #[message]
    message: &'static str,

    // Multiple advices
    #[advice]
    first_advice: LogAdvice<MarkupBuf>,

    #[advice]
    code_frame: CodeFrameAdvice<String, TextRange, String>,

    #[verbose_advice]
    verbose_help: LogAdvice<MarkupBuf>,
}

Add Tags to Diagnostics

#[derive(Debug, Diagnostic)]
#[diagnostic(
    severity = Warning,
    tags(FIXABLE, DEPRECATED_CODE)  // Add diagnostic tags
)]
struct MyDiagn
Read more
Ships withbiome

A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP.

Get the whole plugin
Stats
25,543
Stars
1,180
Forks
Active
Maintenance
Rust
Language
Apache-2.0
License
7h ago
Last commit
3y ago
Created

Repo: biomejs/biome

Other skills on biome.