Automated summary
A guide for writing clear, actionable diagnostics inside the Biome codebase, covering the Diagnostic trait, advice types, and the RuleDiagnostic builder.
Strengths
- Provides complete Rust examples using the #[derive(Diagnostic)] macro and the Advices trait implementation
- Documents the built-in advice types (LogAdvice, CodeFrameAdvice, DiffAdvice, CommandAdvice) and their fields
- Frames diagnostic authoring around three questions: what, why, and how to fix
- Points to the RuleDiagnostic builder pattern that most lint rules actually use
Limitations
- Tightly coupled to the Biome repository and its internal crates (biome_diagnostics, biome_analyze), so it is not portable
- Assumes solid Rust knowledge and familiarity with derive macros
- Does not cover diagnostic testing or snapshot updates
Use it when adding or refining a diagnostic for a Biome lint rule.
Avoid it for designing error messages in projects outside Biome or in languages other than Rust.
Security analysis
SafeThis is a pure documentation/instruction guide describing Biome's diagnostic APIs with Rust code examples. No allowed-tools are declared, and there are no shell commands, network calls, file deletions, credential handling, or obfuscated payloads. The code samples are illustrative constructs (derive macros, markup!, RuleDiagnostic builders) that a coding agent would write into a repo, not execute destructively. No meaningful execution risk.
No concerns found
How this analysis is madeExamples
In Biome, add a diagnostic to the noVar lint rule that tells the user to use 'let' or 'const', with an advice mentioning 'const' when the variable is never reassigned.Review my RuleDiagnostic implementation in crates/biome_analyze and make the advice messages more actionable, following Biome's show-don't-tell principles.I want to suggest an automatic fix for this Biome rule — should I use DiffAdvice or CodeFrameAdvice, and how do I wire it into the diagnostic?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
- Read
crates/biome_diagnostics/CONTRIBUTING.mdfor concepts - Understand Biome's Technical Principles
- Follow the "show don't tell" philosophy
Diagnostic Principles
- Explain what - State what the error is (diagnostic message)
- Explain why - Explain why it's an error (advice notes)
- 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 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 MyDiagnostic {
// ...
}
Available tags:
FIXABLE- Diagnostic has fix informationINTERNAL- Internal error in BiomeUNNECESSARY_CODE- Code is unusedDEPRECATED_CODE- Code uses deprecated features
Best Practices
Message Guidelines
Good messages:
// Good - specific and actionable
"Use 'let' or 'const' instead of 'var'"
// Good - explains why
"This variable is never reassigned, consider using 'const'"
// Good - shows what to do
"Remove the unused import statement"
Bad messages:
// Bad - too vague
"Invalid syntax"
// Bad - just states the obvious
"Variable declared with 'var'"
// Bad - no guidance
"This code has a problem"
Advice Guidelines
Show, don't tell:
// Good - shows code frame
CodeFrameAdvice {
path: "file.js",
span: node.text_range(),
source_code: source,
}
// Less helpful - just text
LogAdvice {
category: LogCategory::Info,
text: markup! { "The expression at line 5 is always truthy" },
}
Provide actionable fixes:
// Good - shows exact change
DiffAdvice {
diff: text_edit, // AsRef<TextEdit>
}
// Less helpful - describes change
LogAdvice {
category: LogCategory::Info,
text: markup! { "Change 'var' to 'const'" },
}
Severity Levels
Choose appropriate severity:
// Fatal - Biome can't continue
severity = Fatal
// Error - Must be fixed (correctness, security, a11y)
severity = Error
// Warning - Should be fixed (suspicious code)
severity = Warning
// Information - Style suggestions
severity = Information
// Hint - Minor improvements
severity = Hint
Common Patterns
// Pattern 1: Simple diagnostic with note
RuleDiagnostic::new(
rule_category!(),
node.range(),
markup! { "Main message" },
)
.note(markup! { "Additional context" })
// Pattern 2: Diagnostic with code frame
RuleDiagnostic::new(
rule_category!(),
node.range(),
markup! { "Main message" },
)
.detail(
node.syntax().text_range(),
markup! { "This part is problematic" }
)
// Pattern 3: Diagnostic with link
RuleDiagnostic::new(
rule_category!(),
node.range(),
markup! { "Main message" },
)
.note(markup! {
"See "<Hyperlink href="https://biomejs.dev/linter">"documentation"</Hyperlink>"."
})
// Pattern 4: Conditional advice
impl Advices for MyAdvice {
fn record(&self, visitor: &mut dyn Visit) -> std::io::Result<()> {
if self.show_hint {
visitor.record_log(
LogCategory::Info,
&markup! { "Hint: ..." }
)?;
}
Ok(())
}
}
Tips
- Category format: Use
area/group/ruleNameformat (e.g.,lint/correctness/noVar) - Markup formatting: Use
markup!macro for all user-facing text - Hyperlinks: Always link to documentation for more details
- Code frames: Include for spatial context when helpful
- Multiple advices: Chain multiple pieces of information
- Verbose advices: Use for extra details users can opt into
- Description vs Message: Description for plain text contexts (IDE popover), message for rich display
- Register categories: Don't forget to add to
categories.rs
References
- Full guide:
crates/biome_diagnostics/CONTRIBUTING.md - Technical principles: https://biomejs.dev/internals/philosophy/#technical
- Diagnostic trait:
crates/biome_diagnostics/src/diagnostic.rs - Advice types:
crates/biome_diagnostics/src/advice.rs - Examples: Search for
#[derive(Diagnostic)]in codebase
From the file to a first result
The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.
View the source and supporting filesThis download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.
1. Download the file
Download SKILL.mdFrom the root of a test project, save the file as .skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.
Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.
mkdir -p '.skill-downloads/biome-diagnostics-development-mryiqidp' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/biome-diagnostics-development-mryiqidp/download' --output '.skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md.part' && mv '.skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md.part' '.skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md'2. Check prerequisites
Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.
Environment declared by the author: Designed for coding agents working on the Biome codebase (github.com/biomejs/biome).
Original excerpt: Prerequisites
- Read
crates/biome_diagnostics/CONTRIBUTING.mdfor concepts - Understand Biome's Technical Principles
- Follow the "show don't tell" philosophy
The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.
3. Load the skill
After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.
Claude Code
test -f '.skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md' && test -s '.skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/diagnostics-development' && cp -R '.skill-downloads/biome-diagnostics-development-mryiqidp' '.claude/skills/diagnostics-development'Cursor
test -f '.skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md' && test -s '.skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/diagnostics-development' && cp -R '.skill-downloads/biome-diagnostics-development-mryiqidp' '.cursor/skills/diagnostics-development'Codex
test -f '.skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md' && test -s '.skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/diagnostics-development' && cp -R '.skill-downloads/biome-diagnostics-development-mryiqidp' '.agents/skills/diagnostics-development'OpenSkills
OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.
Official OpenSkills installationopenskills install './.skill-downloads/biome-diagnostics-development-mryiqidp'openskills read 'biome-diagnostics-development-mryiqidp'Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.
For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.
openskills syncManual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.
4. Try a first task
Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:
Read .skill-downloads/biome-diagnostics-development-mryiqidp/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.
React Hook Form Best Practices
Development
Master React Hook Form: avoid anti-patterns, manage subscriptions, and handle reset, dirty state, and controlled inputs correctly.
Emotion to Mantine Migration
Development
Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports.
Scope Creep Detector
Development
Analyzes git diffs against a stated intent to detect scope creep, unrelated files, broad PRs, and oversized changes, then suggests keep, split, or justify actions.