Skip to content
Development
Skill

/howto-code-in-rust

Use when writing, reviewing, or modifying Rust code - covers error handling with thiserror+miette, type system patterns, async and serde conventions, testing crates, dependency pinning, and module organization

From plugin
ed3d-plugins
25342 skills14 agents6 commands1 MCP

Claude Code

$ npx -y skills add ed3dai/ed3d-plugins --skill howto-code-in-rust --agent claude-code

SKILL.md

howto-code-in-rust.SKILL.md
name: howto-code-in-rust
description: Use when writing, reviewing, or modifying Rust code - covers error handling with thiserror+miette, type system patterns, async and serde conventions, testing crates, dependency pinning, and module organization

Writing Rust

Overview

Rust house style. Applies whenever writing, reviewing, or modifying Rust code.

The two governing values: correctness over convenience, and pragmatic incrementalism. Use the type system aggressively to make invalid states unrepresentable, then evolve the design as patterns repeat rather than building speculative abstractions.

Correctness over convenience

  • Model the full error space. No shortcuts or simplified error handling.
  • Handle all edge cases: race conditions, signal timing, platform differences.
  • Use the type system to encode correctness constraints (newtypes, exhaustive matching, `#[must_use]`).
  • Prefer compile-time guarantees over runtime checks where possible.
  • When uncertain, explore and iterate rather than assume.

User-facing error quality

Standard pairing: `thiserror` for structured error enums, `miette` for user-facing diagnostics with source spans, help text, and related errors. They are complementary -- `thiserror` defines the shape, `miette` adds the diagnostic layer on top.

#[derive(Debug, thiserror::Error, miette::Diagnostic)]
enum ConfigError {
    #[error("failed to parse config at {path}")]
    #[diagnostic(help("check that the file is valid TOML"))]
    Parse { path: String, #[source] source: toml::de::Error },
}

Rules:

  • Group errors by category with an `ErrorKind` enum when a single error type covers many failure modes.
  • Two-tier error model: user-facing errors get semantic exit codes and rich diagnostics; internal errors (programming bugs) may panic or use internal error types.
  • Error display messages are lowercase sentence fragments suitable for composing as "failed to {message}".
  • Cross-platform consistency. Use OS-native logic rather than emulating Unix on Windows or vice versa.
  • User-facing messages in clear, present tense.
  • **Never silently drop unsupported content.** When translating or adapting data between formats, return `Err` for content the target format cannot represent. Silent data loss is a correctness bug. If a caller wants to ignore unsupported content, they can explicitly choose to -- but the library must surface the problem.

Type system patterns

Encode invariants in types:

  • **Newtypes** for domain types. Wrap primitive types to prevent misuse: `struct UserId(u64)` instead of bare `u64`.
  • **Builder patterns** for complex construction with many optional parameters.
  • **Type states** encoded in generics when state transitions matter and invalid states should be unrepresentable.
  • **Lifetimes** to avoid unnecessary cloning. Prefer borrows when data has a natural tree structure.
  • **Restricted visibility.** Use `pub(crate)` and `pub(super)` liberally. Default to the narrowest visibility that works.
  • **`#[non_exhaustive]`** on public types in library crates that have stable APIs. Allows adding variants or fields without a breaking change. Internal crates do not need it.

For concurrent code, use message passing or the actor model to avoid data races rather than shared mutable state behind locks.

Pragmatic incrementalism

  • Prefer specific, composable logic over abstract frameworks. Do not be overly generic.
  • Document non-obvious design decisions and trade-offs in code or commit messages.
  • Do not build for hypothetical future requirements. Rule of three: do not abstract until you have seen the pattern three times.

Research before guessing

When you encounter an unfamiliar crate, an unclear API, or a build problem you cannot immediately diagnose, use research agents rather than iterating by trial and error. Speculative iteration wastes build cycles and context.

  • `ed3d-research-agents:internet-researcher` for crate documentation, API behavior, and ecosystem conventions.
  • `ed3d-research-agents:remote-code-researcher` for examining external repositories for patterns and reference implementations.

These run in isolated context and return summaries, so they do not pollute working context.

Testing

  • Test comprehensively, including edge cases, race conditions, and platform differences.
  • Reuse existing test facilities. Before writing new test helpers, check whether the codebase already has what you need.
  • Unit tests belong in the same file as the code they test, inside a `#[cfg(test)] mod tests` block.
  • Integration tests and fixtures go in `tests/` at the crate root, not mixed with production sources.

Never skip tests

Tests must never silently skip. If a test requires an environment variable, API key, fixture file, or any other external input, it must **fail with a clear error message** when that input is unavailable. Never use patterns like `let Some(...) = ... else { return }` or `#[ignore]` or early-return guards that turn a missing dependency into a silent pass. A green test suite must mean every test actually ran and verified something. If a test cannot run, it must be red, not invisible.

Preferred testing crates

| Crate | Purpose | |-------|---------| | `test-case` | Parameterized tests. Annotate a single function with multiple input/output cases. | | `proptest` | Property-based testing. Generates random inputs to find edge cases you would not write by hand. | | `insta` | Snapshot testing. Captures complex output and diffs against stored snapshots. | | `pretty_assertions` | Better assertion output. Colored diffs instead of raw `Debug` output on failure. |

Serde patterns

  • Use `serde_ignored` to detect unused or typo'd fields in configuration deserialization.
  • Never use `#[serde(flatten)]`. The internal buffering breaks `serde_ignored` warnings, silently swallowing typos in config files.
  • Never use `#[serde(untagged)]` for deserializers. It produces useless error messages like "data did not m
Read more
@ed3dai
Ships withed3d-plugins

Ed's repo of Claude Code plugins, centered around a research-plan-implement workflow. Only a tiny bit cursed. If you're lucky.

25342 skills14 agents1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
253
Star history of ed3dai/ed3d-plugins on GitHub, a chart by star-history.com

Other skills on ed3d-plugins.

creating-a-plugin

creating-a-plugin

Use when creating a new Claude Code plugin or setting up plugin structure - provides complete file organization, manifest format,…

@ed3dai@ed3daiInstall Skill
creating-an-agent

creating-an-agent

Use when creating specialized subagents for Claude Code plugins or the Task tool - covers description writing for…

@ed3dai@ed3daiInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about howto-code-in-rust.

Which coding agents can use howto-code-in-rust?
howto-code-in-rust installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.