ワンクリックで
rust-style
General Rust conventions for Pluto. Use it once for understanding the codebase better.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
General Rust conventions for Pluto. Use it once for understanding the codebase better.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Use when porting Charon components to understand Go codebase architecture, workflow, design patterns, or component responsibilities
Pluto-specific code review guidelines. Use as a general guideline when asked to conduct a code review.
Guides Go→Rust porting for Pluto. Invoke when asked to port, implement parity for, or translate a Go component.
Full multi-agent code review for a Pluto PR. Spawns parallel agents covering functional correctness, security, Rust style, and code quality, then posts all findings as isolated GitHub review comments and submits a final approve/request-changes verdict. Invoke as `/review-pr <PR-number>` or `/review-pr <GitHub-PR-URL>`.
Iteratively review and fix a Pluto PR until it is "ideal" — drives the /review-pr multi-agent pipeline inside /ralph-loop, applying fixes between iterations and never posting inline comments. After the loop terminates, posts a single summary comment to the GitHub PR with everything that was resolved. Invoke as `/loop-review-pr <PR-number|PR-URL> [--max-iterations N]`.
Use when implementing, reviewing, debugging, or explaining Pluto Rust libp2p code: Node/P2PContext ownership, PlutoBehaviour composition, NetworkBehaviour and ConnectionHandler protocols, relay/force-direct/quic-upgrade behaviours, peerinfo/parsigex protocol handlers, DKG protocol handlers, and P2P tests.
| name | rust-style |
| description | General Rust conventions for Pluto. Use it once for understanding the codebase better. |
Run from pluto/ before declaring any work done:
cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-features
cargo deny check
All must pass clean.
Define module-local error enums with thiserror:
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("message: {0}")]
Variant(String),
#[error(transparent)]
Underlying(#[from] OtherError),
}
pub type Result<T> = std::result::Result<T, Error>;
Rules:
errors.New("msg") → enum variant with #[error("msg")] (match strings exactly)errors.Wrap(err, "...") → #[from] / #[source] where appropriate#[error("...")] format string. If a field is not surfaced in the error message, either include it or remove it from the variant. Dead payload (captured but never displayed) is not allowed.?; never swallow errors with .ok() or filter_map in production codeunwrap(), expect(), panic!() outside of test codeanyhow in library crates; use typed errors everywhereAll arithmetic must be checked — arithmetic_side_effects = "deny" is enforced:
// Bad
let x = a + b;
// Good
let x = a.checked_add(b).ok_or(Error::Overflow)?;
Never use as for numeric type conversions — use fallible conversions with try_from:
// Bad - will cause clippy errors
let x = value as u32;
let y = some_usize as u64;
// Good - use try_from with proper error handling
let x = u32::try_from(value)?;
let y = u64::try_from(some_usize).expect("message explaining why this is safe");
Rules:
TryFrom/try_from for numeric conversions between different types? or expect with justification)expect is when the conversion is guaranteed to succeed (e.g., usize to u64 on 64-bit platforms)as casts: cast_possible_truncation, cast_possible_wrap, cast_sign_lossWhen implementing a conversion, implement TryFrom (not TryInto) and From (not Into):
// Bad - implementing TryInto directly
impl TryInto<Foo> for Bar {
type Error = Error;
fn try_into(self) -> Result<Foo, Error> { /* ... */ }
}
// Good - implement TryFrom; the matching TryInto comes for free
impl TryFrom<Bar> for Foo {
type Error = Error;
fn try_from(value: Bar) -> Result<Foo, Error> { /* ... */ }
}
Rules:
TryFrom<A> for B / From<A> for B. The standard library's blanket impls then provide TryInto/Into automatically; the reverse is not true.TryInto/Into so callers that implement only those traits still work.async/await for I/O and network-bound code; use Tokio as the runtime.tokio::fs / tokio::io instead of blocking std::fs / std::io.tokio::task::spawn_blocking.tokio::sync::*) over std::sync::* when tasks may .await.tokio::time for timeouts, sleeps, and intervals (avoid std::thread::sleep).snake_case, types PascalCase, constants SCREAMING_SNAKE_CASE.format!("hello {name}")format!("hello {}", name)// TODO: and remove before PR merge.Prefer generic parameters over concrete types when a function only needs the behavior of a trait. This mirrors the standard library's own conventions and makes functions callable with a wider range of inputs without extra allocations.
| Instead of | Prefer | Accepts |
|---|---|---|
&str | impl AsRef<str> | &str, String, &String, … |
&Path | impl AsRef<Path> | &str, String, PathBuf, &Path, … |
&[u8] | impl AsRef<[u8]> | &[u8], Vec<u8>, arrays, … |
&Vec<T> | impl AsRef<[T]> | Vec<T>, slices, arrays, … |
String (owned, read-only) | impl Into<String> | &str, String, … |
Examples:
// accepts &str, String, PathBuf, &Path, …
fn read_file(path: impl AsRef<std::path::Path>) -> std::io::Result<String> {
std::fs::read_to_string(path.as_ref())
}
// accepts &str, String, &String, …
fn print_message(msg: impl AsRef<str>) {
println!(“{}”, msg.as_ref());
}
// accepts &[u8], Vec<u8>, arrays, …
fn hash_bytes(data: impl AsRef<[u8]>) -> [u8; 32] {
sha256(data.as_ref())
}
Rules:
.as_ref() once at the top of the function and bind it to a local variable when the value is used in multiple places.impl AsRef<T> if the function immediately converts to an owned type anyway — use impl Into<T> (or just accept the owned type) in that case.#[tokio::test] for async tests.test-case for repeated/parameterized tests (including async):#[cfg(test)]
mod tests {
use test_case::test_case;
#[test_case(1, 2 ; "small")]
#[test_case(10, 20 ; "large")]
fn adds(a: u64, b: u64) {
let _ = (a, b);
}
#[test_case("a" ; "case_a")]
#[test_case("b" ; "case_b")]
#[tokio::test]
async fn async_cases(input: &str) {
let _ = input;
}
}
Apply when reviewing or porting code:
Ordering::SeqCst is justified; prefer Relaxed/AcqRel for
standalone flags.Error::Io wraps std::io::Error (not String) to preserve
ErrorKind.impl AsRef<[u8]> / impl AsRef<str>
rather than concrete slice refs where appropriate.unwrap() / expect() / panic!() outside test code.checked_add, checked_mul, …).use declarations appear before all other items in each file.#[error("...")] string).TryFrom/From rather than TryInto/Into
(not caught by Clippy for TryInto).