Install
openclaw skills install serde-code-reviewReviews serde serialization code for derive patterns, enum representations, custom implementations, and common serialization bugs. Use when reviewing Rust code that uses serde, serde_json, toml, or any serde-based serialization format. Covers attribute macros, field renaming, and format-specific pitfalls.
openclaw skills install serde-code-reviewderive, rc), format crates (serde_json, toml, bincode, etc.), and Rust edition (2024 has breaking changes affecting serde code)Serialize and Deserialize are derived appropriatelygen keyword, RPIT lifetime capture changes, never_type_fallbackRun in order. Do not write a finding until the step that applies has passed.
Serde context on disk — Pass when: You have read the relevant Cargo.toml (crate or workspace root) and can state Rust edition, serde / serde_derive features if non-default (derive, rc), and which format crates apply (serde_json, toml, bincode, etc.) for the code under review. Then apply edition-specific checklist items (e.g. gen, RPIT/never_type_fallback) only when that file supports them.
Per-finding evidence — Pass when: Each issue cites [FILE:LINE] from the current tree for the struct/enum, Serialize/Deserialize impl, or attribute block in question (not from memory, docs-only, or another branch).
Category check vs protocol — Pass when: For the finding type (derive attrs, enum tagging, flatten, custom impl, sqlx + serde alignment), you ran the matching checks from the review-verification-protocol skill (e.g. full type definition + serde attrs before “wrong representation”; confirmed edition in Cargo.toml before edition-2024-only findings). Then add the finding.
Output shape — Pass when: The report lines match Output Format below (severity + description).
Report findings as:
[FILE:LINE] ISSUE_TITLE
Severity: Critical | Major | Minor | Informational
Description of the issue and why it matters.
| Issue Type | Reference |
|---|---|
| Derive patterns, attribute macros, field configuration | references/derive-patterns.md |
| Custom Serialize/Deserialize, format-specific issues | references/custom-serialization.md |
#[derive(Serialize, Deserialize)] on types that cross serialization boundaries#[derive(Debug)] alongside serde derives (debugging serialization issues)#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]#[expect(unused)] over #[allow(unused)] for serde-only fields (self-cleaning lint suppression, stable since 1.81)#[serde(rename_all = "...")] used consistently across the API#[serde(skip_serializing_if = "Option::is_none")] for optional fields (clean JSON output)#[serde(default)] for fields that should have fallback values during deserialization#[serde(rename = "...")] when Rust field names differ from wire format#[serde(flatten)] used judiciously (can cause key collisions)#[serde(deny_unknown_fields)] on types that need forward compatibilitygen — reserved keyword in edition 2024 (use r#gen or rename)#[derive(sqlx::Type)] enums use consistent representation with serderename_all) and sqlx (rename_all)gen (reserved keyword — use r#gen with #[serde(rename = "gen")] or choose a different name)Serialize/Deserialize impls returning impl Trait account for RPIT lifetime capture changes (all in-scope lifetimes captured by default; use + use<'a> for precise control)never_type_fallback — ! falls back to ! instead of (), which affects match exhaustiveness on Result<T, !> patternsPartialEq derived for types with round-trip testsf64 → i64 in JSON numbers)Decimal used for money/precision-sensitive values, not f64#[serde(rename)] causing API-breaking field name changes#[serde(flatten)] causing silent key collisionsf64 precision loss for monetary values)rename_all across related types (confusing API)skip_serializing_if causing null/empty noise in outputdeny_unknown_fields on types consumed by evolving APIs (breaks forward compatibility)gen without r#gen escape (edition 2024 compile failure)#[serde(default)] on required fields#[allow(unused)] instead of #[expect(unused)] for serde-only fields (prefer self-cleaning lint suppression)#[non_exhaustive] alongside serde for forward compatibility#[serde(untagged)] enums — Valid when discriminated by structure, not by tagserde_json::Value for dynamic data — Appropriate for truly schema-less fields#[serde(skip)] on computed fields — Correct for derived/cached values#[serde(with = "...")] for custom formats — Standard for dates, UUIDs, etc.r#gen with #[serde(rename = "gen")] — Correct edition 2024 workaround for gen fields in wire formats+ use<'a> on custom serializer return types — Precise RPIT lifetime capture (edition 2024)Complete Gates (before reporting findings) above; gate 3 incorporates the review-verification-protocol skill for serde-related issue types.