Claude Code Plugins

Community-maintained marketplace

Feedback

Create new Rust crates in this Cargo workspace following established patterns for dependency management, testing, documentation, and project structure. Use when adding new workspace members, creating modules, or structuring code. Keywords: cargo, crate, workspace, module, new crate, add crate, dependency, Rust project

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md


name: rust-crate-creator description: Create new Rust crates in this Cargo workspace following established patterns for dependency management, testing, documentation, and project structure. Use when adding new workspace members, creating modules, or structuring code. Keywords: cargo, crate, workspace, module, new crate, add crate, dependency, Rust project

Rust Crate Creator

Creates new Rust crates in the workspace following established project conventions for dependency management, testing, documentation, and modular architecture.

Instructions

When creating a new crate, follow this structured approach:

1. Analyze Workspace Structure

Workspace root patterns:

  • All dependencies must be pinned in Cargo.toml:[workspace.dependencies]
  • Workspace members live under crates/
  • Use resolver = "2" for workspace-level dependency resolution
  • Generate artifacts belong in target/ (never commit)

Current workspace dependencies to reference:

[workspace.dependencies]
# Internal crates (always use path references)
common = { path = "crates/common" }
expr = { path = "crates/expr" }
types = { path = "crates/types" }

# External dependencies (pin versions here)
proptest = "1.9.0"
pretty_assertions = "1"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.145"
sqlparser = "0.43"
tempfile = "3.23.0"
thiserror = "1.0.69"
ahash = "0.8.12"
hashbrown = { version = "0.14.5", features = ["serde"] }
uuid = { version = "1.18.1", features = ["serde", "v4"] }
bincode = { version = "2.0.1", features = ["serde"] }
bytes = "1.10.1"

2. Create Crate Structure

Directory layout:

crates/<crate-name>/
├── Cargo.toml
├── CLAUDE.md
├── AGENTS.md
├── src/
│   ├── lib.rs
│   └── tests.rs (or mod tests in lib.rs)
└── tests/ (optional integration tests)

Cargo.toml template:

[package]
name = "crate-name"
version = "0.1.0"
edition = "2024"  # or "2021" if needed

[dependencies]
# Reference workspace deps with { workspace = true }
common = { workspace = true }
types = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
# Test dependencies also from workspace
tempfile = { workspace = true }
proptest = { workspace = true }
pretty_assertions = { workspace = true }

Critical rules:

  • NEVER specify versions in member crates—always use { workspace = true }
  • Even path-only dependencies (common, expr, types) must use workspace references
  • Add new dependencies to root [workspace.dependencies] first, then reference them

3. Generate CLAUDE.md (Crate Guidelines)

Template structure:

# [Crate Name] Guidelines

## Role Within The Workspace
- Purpose and responsibility of this crate
- How it integrates with other workspace members
- Key contracts and APIs it provides

## Integration Contracts
- **Parser** – How parser interacts with this crate
- **Types** – Type dependencies and shared structures
- **Common** – Error handling and shared utilities
- **Storage/Catalog/Expr** – Domain-specific integrations

## Module Layout & Extension Points
- Key source files and their responsibilities
- How to add new features or extend existing ones
- Important patterns to follow

## Build, Test, and Development Commands
- `cargo check -p [crate-name]` — fast validation
- `cargo test -p [crate-name]` — run crate tests
- `cargo fmt` / `cargo fmt -- --check` — formatting
- `cargo clippy -p [crate-name] --all-targets` — linting
- `scripts/coverage.sh -- --package [crate-name]` — coverage

## Coding Style & Naming Conventions
- Follow rustfmt defaults (4-space indent, trailing commas)
- Modules: snake_case (`mod storage_backend`)
- Types/traits: UpperCamelCase (`SqlValue`)
- Constants: SCREAMING_SNAKE_CASE
- Workspace dependency pattern: `{ workspace = true }`

## Testing Guidelines
- Co-locate unit tests using `mod tests`
- Use `tempfile::tempdir()` for filesystem tests
- Property tests with `proptest` (name as `prop_*`)
- Integration tests in `tests/` directory
- Run tests before commits

## Commit & Pull Request Guidelines
- Imperative mood commits
- PRs include: motivation, changes, validation commands, affected crates
- Mention downstream impacts

4. Generate AGENTS.md (Implementation Guardrails)

Template structure:

# [Crate Name] - agents.md

> Implementation guardrails for the `[crate-name]` crate so future agents can extend it without breaking workspace conventions.

## Purpose

- Core responsibility and domain
- Key abstractions provided
- Integration points with other crates

## Architecture checkpoints

1. **Key pattern 1** - Description and constraints
2. **Key pattern 2** - Description and constraints
3. **Key pattern 3** - Description and constraints

## Workspace coordination

- Dependencies must be declared via `{ workspace = true }`
- Shared domain types come from `common`/`types`
- Tests rely on `tempfile` for temporary directories
- All errors use `common::DbResult` and `DbError` variants

## Extending the crate

- How to add new features safely
- Patterns to maintain consistency
- Integration points to coordinate with other crates

By following these constraints we keep the [crate-name] layer aligned with the rest of the SQL database workspace.

5. Add Rust Documentation Comments

Module-level docs (in lib.rs):

//! Brief description of the crate's purpose.
//!
//! # Examples
//!
//! ```
//! // Show basic usage
//! ```
//!
//! # Architecture
//!
//! Explain key design decisions or patterns.

Type/function docs:

/// Brief description of what this does.
///
/// # Examples
///
/// ```
/// let example: TypeName = ...;
/// // Show usage
/// ```
///
/// # Errors
///
/// Returns `DbError::...` when conditions occur.
pub struct TypeName { ... }

/// Identifier for a column within a table schema.
/// Examples:
/// - `let id_col: ColumnId = 1; // maps to "id"`
/// - `let name_col: ColumnId = 2; // maps to "name"`
pub type ColumnId = u64;

6. Set Up Testing Patterns

Unit tests (co-located):

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn descriptive_test_name() {
        // Arrange

        // Act

        // Assert
    }
}

Using tempfile for filesystem tests:

use tempfile::tempdir;

#[test]
fn test_with_temp_directory() {
    let dir = tempdir().unwrap();
    let path = dir.path().join("test.file");

    // Use path for testing

    // dir automatically cleaned up on drop
}

Property-based tests:

use proptest::prelude::*;

proptest! {
    #[test]
    fn prop_roundtrip_preserves_value(input: Vec<u8>) {
        let encoded = encode(&input);
        let decoded = decode(&encoded).unwrap();
        prop_assert_eq!(input, decoded);
    }
}

7. Update Workspace Configuration

Add to root Cargo.toml members:

[workspace]
members = [
    # ... existing members
    "crates/new-crate-name",
]

Add internal dependency to workspace:

[workspace.dependencies]
new-crate-name = { path = "crates/new-crate-name" }

8. Code Coverage Setup

The project uses cargo-llvm-cov for coverage:

Run coverage for specific crate:

scripts/coverage.sh -- --package crate-name

Coverage generates:

  • HTML report: target/llvm-cov/html/index.html
  • LCOV format: target/llvm-cov/lcov.info

9. Common Patterns

Error handling:

use common::{DbError, DbResult};

pub fn operation() -> DbResult<T> {
    // ... implementation
    Err(DbError::CrateName(format!("descriptive error")))
}

Serialization with bincode:

use bincode::config::{self, Config};
use bincode::serde::{decode_from_slice, encode_to_vec};

fn bincode_config() -> impl Config {
    config::legacy()
}

// Encoding
let bytes = encode_to_vec(data, bincode_config())?;

// Decoding
let (decoded, read) = decode_from_slice(&bytes, bincode_config())?;

Module organization:

// src/lib.rs
pub mod submodule;

pub use submodule::PublicType;

// src/submodule.rs
use common::{DbError, DbResult};

pub struct PublicType { ... }

#[cfg(test)]
mod tests { ... }

Common Pitfalls and Solutions

Test Module Configuration

Problem: Tests fail to compile with "unresolved import" errors for dev-dependencies.

Solution: Always add #[cfg(test)] attribute to test modules:

#[cfg(test)]
mod tests;

This ensures test-only imports (like tempfile) are only compiled during test runs.

File I/O and Clippy Warnings

Problem: Clippy warns about "file opened with create, but truncate behavior not defined".

Solution: Explicitly specify truncate behavior when using create(true):

// For append-only files (don't truncate existing content)
OpenOptions::new()
    .read(true)
    .write(true)
    .create(true)
    .truncate(false)  // Keep existing content
    .open(&path)?;

// For overwriting files
OpenOptions::new()
    .write(true)
    .create(true)
    .truncate(true)   // Overwrite existing content
    .open(&path)?;

Page Allocation and File Extension

Problem: Sequential ID allocation fails because the file doesn't actually extend until data is written.

Solution: Write the page to disk immediately after allocation to reserve the space:

fn allocate_page(&mut self, table: TableId) -> DbResult<PageId> {
    let pid = PageId(file_len / PAGE_SIZE);
    let page = Page::new(pid.0);

    // Write immediately to extend the file
    self.write_page(table, &page)?;

    // Then add to cache
    self.cache.push((table, pid), page);
    Ok(pid)
}

Coverage Script Usage

Problem: Running scripts/coverage.sh -- --package crate-name fails with "Unrecognized option: 'package'".

Solution: Use cargo llvm-cov directly for single-crate coverage:

# Correct approach
cargo llvm-cov --package crate-name --html

# View summary
cargo llvm-cov --package crate-name --summary-only

The workspace scripts/coverage.sh is designed for full workspace coverage, not filtered runs.

Import Organization

Problem: Rustfmt reorders imports in unexpected ways.

Solution: Follow rustfmt's preference:

  • External crates first (alphabetically)
  • Then standard library imports
  • Import items alphabetically within each use statement
use common::{DbError, DbResult, PageId, TableId};
use hashbrown::HashMap;
use lru::LruCache;
use std::{
    fs::OpenOptions,
    io::{Read, Seek, SeekFrom, Write},
    num::NonZeroUsize,
    path::PathBuf,
};
use storage::{PAGE_SIZE, Page};  // Items sorted alphabetically

Function Coverage Targets

Problem: Coverage shows low function coverage (e.g., 50%) even when tests seem comprehensive.

Solution: Test error paths and edge cases explicitly:

  • Test functions that return Result<T> with both success and error cases
  • Test private helper functions indirectly through public API
  • Add tests for all public trait implementations
  • Test panic conditions with #[should_panic]
  • Target 90%+ line coverage and 85%+ function coverage

Example:

#[test]
fn test_error_path() {
    let result = operation_that_can_fail();
    assert!(matches!(result, Err(DbError::Storage(_))));
}

#[test]
#[should_panic(expected = "descriptive message")]
fn test_panic_condition() {
    function_that_panics();
}

Validation Checklist

Before completing crate creation:

  • Cargo.toml uses { workspace = true } for all dependencies
  • Added to workspace members in root Cargo.toml
  • CLAUDE.md documents integration contracts
  • AGENTS.md captures architecture guardrails
  • Module-level doc comments (//!) in lib.rs
  • Type/function doc comments (///) with examples
  • Unit tests use mod tests pattern
  • Filesystem tests use tempfile::tempdir()
  • Error types use common::DbError variants
  • cargo check -p crate-name passes
  • cargo test -p crate-name passes
  • cargo fmt -- --check passes
  • cargo clippy -p crate-name --all-targets passes
  • cargo llvm-cov --package crate-name --summary-only shows 85%+ function coverage
  • cargo llvm-cov --package crate-name --summary-only shows 90%+ line coverage
  • Error paths and edge cases are explicitly tested

Output Format

When creating a new crate, generate files in this order:

  1. Show workspace analysis - List existing crates and dependencies
  2. Create directory structure - Use Write tool for Cargo.toml, CLAUDE.md, AGENTS.md
  3. Generate src/lib.rs - With proper doc comments
  4. Add tests - Either in-module or separate tests.rs
  5. Update workspace - Modify root Cargo.toml
  6. Run validation - Execute check/test/fmt/clippy
  7. Summary - List created files and next steps

Example Usage

User: "Create a new crate for query planning"