AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Rust Style

skill-furedea-agent-harness-rust-style · by furedea

>

No reviews yet
0 installs
17 views
0.0% view→install

Install

$ agentstack add skill-furedea-agent-harness-rust-style

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-furedea-agent-harness-rust-style)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
17d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Rust Style? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Rust Coding Style Guidelines

Scope

This skill governs code written inside an already-bootstrapped Rust project: package commands, module layout, test authoring, refactoring, code review, naming, ownership, errors, filesystem operations, comments, and docs.

Project bootstrap (flake.nix, direnv, initial Cargo.toml, initial rust-toolchain.toml) belongs to the nix-dev-init skill. If the project is not yet bootstrapped, defer to nix-dev-init first and return here once direnv allow succeeds and Cargo is available.

Why the split

Bootstrap is an environment concern. This skill is for day-to-day Rust implementation inside an existing project. Do not duplicate Nix, direnv, or initial Cargo setup rules here.

Package Management

  • Use Cargo for Rust package operations.
  • Add dependencies with cargo add when cargo add is available.
  • Add development dependencies with cargo add --dev .
  • Use cargo check for a fast compile/type-check pass when tests are not needed yet.
  • Use cargo test for the default verification pass.
  • Use cargo clippy --all-targets -- -D warnings for linting.
  • Do not edit Cargo.lock manually.
  • Commit Cargo.lock for applications, CLI tools, and internal tools.
  • For library crates, follow the repository's existing Cargo.lock policy.
  • Do not use @latest-style version shortcuts in documentation or committed commands.
  • Do not add a dependency only because it is common. Add it when it removes real boundary complexity or prevents error-prone code.

Directory Structure

  • Follow Cargo's standard layout.
  • Store production code in src/.
  • Keep src/main.rs thin for binary crates. It should parse CLI arguments and call library code.
  • Put reusable execution logic in src/lib.rs and focused modules under src/.
  • Store integration tests in tests/.
  • Keep unit tests near the module when they need private access.
  • Use examples/ only for runnable examples that should compile.
  • Avoid utils.rs and helpers.rs; name modules by domain or action.

Typical binary crate shape:

src/
├── main.rs
├── lib.rs
├── cli.rs
├── config.rs
├── fs_ops.rs
└── render.rs
tests/
└── cli.rs

File Standards

  • Let rustfmt define formatting. Do not hand-format around rustfmt.
  • Keep files focused and cohesive.
  • Prefer modules of roughly 200-500 lines. Split when multiple responsibilities appear.
  • Keep public items before private helpers when it improves scanning.
  • Use mod.rs only when the existing project already uses that style; otherwise prefer module_name.rs plus module_name/child.rs.
  • Put one top-level concept per file when the concept has real behavior.
  • Keep generated code out of hand-written modules unless the project has a clear generated-code convention.

Testing

  • Use cargo test as the default test command.
  • Write unit tests in the target source file or module with #[cfg(test)] mod tests.
  • Use tests/*.rs for integration tests that exercise public APIs or CLI behavior.
  • Integration tests compile as a separate crate and should use only public APIs.
  • Use doc tests for public examples that should stay compilable.
  • Test edge cases and error paths for new behavior.
  • Add regression tests for bug fixes.
  • Use temporary directories for filesystem tests. Do not touch the real home directory.
  • Snapshot generated artifacts only when exact output is part of the behavior.
  • Keep snapshots small and focused.
  • Do not test behavior that the type system already guarantees.
  • Prefer fake implementations behind traits over broad mocking libraries.
  • Use table-driven tests for the same behavior across multiple inputs.
  • Use async tests only when the project already has an async runtime requirement.

Test Structure

  • Unit test: place next to the implementation in the same file or module.
  • Integration test: place under tests/ when testing public API, CLI behavior, or crate-level wiring.
  • Helper function: prefer local helper functions when setup is lightweight or argument-driven.
  • Shared fixture: keep it in the test module first; move to tests/common/ only when multiple integration test files need it.
  • Fake implementation: prefer explicit fake types over global mocks.
  • Parameterized cases: use a table of cases and loop over it when one behavior has many inputs.

Example unit test layout:

pub fn normalize_name(input: &str) -> String {
    input.trim().replace('_', "-")
}

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

    #[test]
    fn normalize_name_trims_whitespace_and_replaces_underscores() {
        assert_eq!(normalize_name(" rust_style "), "rust-style");
    }
}

Syntax Rules

Module Item Order

  • Put module-level constants before types when they configure the following code.
  • Prefer type aliases and enums before structs that use them.
  • Put public structs, enums, and traits before their implementations.
  • Put public functions before private helper functions.
  • Keep #[cfg(test)] mod tests at the bottom of the file.
  • Keep related types and their impl blocks close together.

Structs

  • Derive Debug for most domain structs.
  • Derive Clone, PartialEq, Eq, Ord, or Hash only when the type actually needs that capability.
  • Keep fields private when the type has invariants.
  • Use constructors for types with validation or normalization.
  • Use tuple structs for narrow newtypes and named-field structs when field names improve clarity.
  • Avoid boolean constructor arguments; prefer an enum or options struct.

Value Object pattern:

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SkillName(String);

impl SkillName {
    pub fn parse(value: impl Into) -> anyhow::Result {
        let value = value.into();
        if value.is_empty() {
            anyhow::bail!("skill name must not be empty");
        }
        Ok(Self(value))
    }

    pub fn as_str(&self) -> &str {
        &self.0
    }
}

Enums

  • Use enums for fixed states, providers, modes, and policy decisions.
  • Convert user input strings into enums at the boundary.
  • Avoid passing raw string modes through the codebase.
  • Prefer exhaustive match statements for domain control flow.
  • Implement Display when the enum has a stable user-facing representation.
  • Implement FromStr or TryFrom when parsing user input.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Provider {
    Claude,
    Codex,
}

Functions and Methods

  • Keep functions focused and small.
  • Prefer borrowing in parameters: &str, &Path, &[T].
  • Return owned values when the function creates or transforms ownership.
  • Use associated functions for pure construction.
  • Keep I/O in module-level functions or dedicated service structs, not inside Value Object constructors.
  • Prefer Result for expected failures.
  • Prefer early returns for guard clauses.
  • Avoid async unless the project has real concurrency or nonblocking I/O requirements.

Getter and Conversion Naming

  • Borrowed views use as_*: as_str, as_path, as_slice.
  • Consuming conversions use into_*: into_inner, into_path_buf.
  • Cheap copies can use the value name directly: len, status, provider.
  • Avoid Java-style get_* unless following an existing local convention.
  • Boolean queries use is_*, has_*, can_*, or should_*.
  • Fallible parsing uses parse, try_from, or from_str.

Ownership and Borrowing

  • Accept impl AsRef only at outer convenience boundaries. Inside the codebase, pass &Path.
  • Accept impl Into for constructors that store owned strings.
  • Do not clone to satisfy the borrow checker until the ownership model is understood.
  • Use Cow only when profiling or API shape shows it is worthwhile.
  • Prefer slices over &Vec in function parameters.

Collections

  • Use Vec for ordered sequences.
  • Use BTreeMap or sorted vectors when deterministic output order matters.
  • Use HashMap when order is irrelevant and lookup dominates.
  • Do not expose mutable collections directly from domain types.

Strings and Formatting

  • Use &str for borrowed string input and String for owned string storage.
  • Use format! when constructing a new owned string from values.
  • Use captured identifiers in formatting when it improves readability: format!("{name}").
  • Prefer to_owned() or String::from when converting a string literal to String.
  • Avoid unnecessary to_string() in hot or repeated code.
  • Keep user-facing text separate from machine-readable output.

Numeric Conversions

  • Use usize for indexing and collection lengths.
  • Do not use as for narrowing integer conversions.
  • Use TryFrom or try_into when a conversion can fail.
  • Use newtypes when a number has a domain unit or invariant.
  • Make lossy conversions explicit in the function or variable name.

Error Handling

  • Use anyhow::Result at application and CLI orchestration boundaries where errors are reported to humans and callers do not branch on error categories.
  • Use concrete error types when callers or tests need to distinguish failure categories.
  • thiserror is appropriate for deriving concrete error types. Do not introduce it just to wrap every possible failure.
  • Add context at I/O, external command, parse, and config boundaries.
  • A low-level error such as "No such file or directory" must include the operation and path.
  • Use ? for propagation.
  • Do not use unwrap or expect in production code except for impossible states justified by a nearby invariant.

Panic Policy

  • Use Result for expected failures.
  • Reserve panic! for logic bugs and impossible states.
  • Avoid direct indexing when missing data is a normal possibility; use get() or explicit validation.
  • Public APIs that can panic must document # Panics.
  • Do not leave todo!, unimplemented!, or debugging panic! calls in production code.
  • Use unreachable! only when the type system or previous validation makes the branch impossible.

Application-boundary error:

use anyhow::{Context, Result};

pub fn read_config(path: &Path) -> Result {
    std::fs::read_to_string(path)
        .with_context(|| format!("failed to read config file {}", path.display()))
}

Distinguishable domain error:

#[derive(Debug, thiserror::Error)]
pub enum ProviderError {
    #[error("unknown provider: {0}")]
    UnknownProvider(String),
}

CLI Code

  • Use typed structs and enums for CLI input.
  • Keep argument parsing separate from execution.
  • Do not perform filesystem or network work while parsing CLI arguments.
  • Human-readable command results go to stdout.
  • Progress, warnings, and diagnostics go to stderr.
  • Machine-readable output must not be mixed with human logs.
  • Keep exit codes coarse but meaningful enough for CI.
#[derive(Debug, clap::Parser)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Command,
}

#[derive(Debug, clap::Subcommand)]
pub enum Command {
    Render(RenderArgs),
    Verify(VerifyArgs),
}

Logging and Diagnostics

  • Short-lived CLI tools may use eprintln! for warnings and progress.
  • Libraries must not initialize global logging.
  • Use tracing only when the project needs structured logs, spans, or long-running diagnostics.
  • Keep human diagnostics on stderr and machine-readable command output on stdout.
  • Include paths, command names, and config keys in diagnostics when they explain the failure.

Filesystem Operations

  • Use Path and PathBuf for paths. Do not build paths with string concatenation.
  • Treat source tree traversal and symlink creation as separate behaviors.
  • Do not follow symlinks while traversing source trees unless the behavior is explicitly required and tested.
  • Use DirEntry::file_type() instead of Path::is_dir() when symlink behavior matters.
  • Keep file-writing operations behind small functions that are easy to test with temporary directories.
  • Distinguish files fully owned by the project from files also modified by users or external tools.
  • Prefer writing to a temporary file and replacing the target when partial writes would be harmful.

Symlink-aware traversal without following symlinks:

use anyhow::{Context, Result};
use std::path::{Path, PathBuf};

pub fn collect_regular_files(dir: &Path) -> Result> {
    let mut files = Vec::new();
    collect_regular_files_into(dir, &mut files)?;
    files.sort();
    Ok(files)
}

fn collect_regular_files_into(dir: &Path, files: &mut Vec) -> Result {
    for entry in std::fs::read_dir(dir)
        .with_context(|| format!("failed to read directory {}", dir.display()))?
    {
        let entry = entry?;
        let file_type = entry.file_type()?;
        let path = entry.path();

        if file_type.is_symlink() {
            continue;
        }
        if file_type.is_dir() {
            collect_regular_files_into(&path, files)?;
        } else if file_type.is_file() {
            files.push(path);
        }
    }
    Ok(())
}

Config and Serialization

  • Use typed structs for project-owned config.
  • Use serde(deny_unknown_fields) where unknown input keys should be rejected.
  • Do not reject unknown keys in external-tool-owned config files.
  • Use #[serde(rename_all = "...")] to keep serialized field naming consistent.
  • Use #[serde(default)] for optional input fields that have stable defaults.
  • Use #[serde(skip_serializing_if = "Option::is_none")] when absent values should not appear in output.
  • Use #[serde(flatten)] sparingly because it makes schemas less explicit.
  • Separate fully generated files from user-owned files that receive managed updates.
  • Do not overwrite user-owned or external-tool-owned config files wholesale.
  • For managed config sync, update only the keys owned by the project and preserve unknown keys.
  • Use stable ordering for generated output when review diffs or tests depend on order.
  • Use a format-preserving edit strategy when comments, ordering, and unknown future keys must be preserved.

Cargo Features

  • Keep feature flags additive. Enabling a feature should not remove behavior.
  • Avoid growing default features unless the behavior is truly the default user expectation.
  • Keep optional dependency features named clearly after the capability they enable.
  • Test important feature combinations explicitly.
  • Consider cargo test --all-features when features affect compiled code paths.
  • Do not use features as a runtime configuration substitute.

Public API Design

  • Reserve pub for APIs intended to be consumed outside the crate.
  • Use pub(crate) for items shared across internal modules, including inside private modules when it clarifies that the item is not an external API.
  • Keep items private when they are only used inside the current module.
  • Keep public APIs smaller than internal APIs.
  • Avoid exposing third-party types in public APIs unless that dependency is part of the intended API.
  • Use #[non_exhaustive] for public enums or structs that may need new variants or fields.
  • Seal traits that downstream crates should not implement.
  • Treat new public trait implementations as semver-relevant changes.
  • Do not expose mutable internal collections directly.

Macro and Build Script Policy

  • Prefer functions, traits, and generics before macros.
  • Add a macro only when it removes repetition that ordinary Rust abstractions cannot express clearly.
  • Avoid procedural macros unless the project has a strong reason for compile-time code generation.
  • Keep test helper macros small and obvious.
  • Do not add build.rs until native linking, environment probing, or code generation is actually required.
  • Generated code should have tests or snapshots that make the generated output reviewable.

Naming Conventions

  • Modules and files: snake_case.
  • Functions, methods, and variables: snake_case.
  • Types, traits, and enum variants: UpperCamelCase.
  • Constants and statics: SCREAMING_SNAKE_CASE.
  • Generic type parameters: shor

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.