OR

organize-modules

Applies clean API patterns to Rust module structures.

Install

mkdir -p .claude/skills/organize-modules && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/2483" && unzip -o skill.zip -d .claude/skills/organize-modules && rm skill.zip

Installs to .claude/skills/organize-modules

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Apply private modules with public re-exports (barrel export) pattern for clean API design. Includes conditional visibility for docs and tests. Use when creating modules, organizing mod.rs files, or before creating commits.
222 chars✓ has a “when” trigger
Intermediate

Key capabilities

  • Apply barrel export pattern for public APIs
  • Implement conditional visibility for docs and tests
  • Organize mod.rs files for clean module structure
  • Control rustfmt behavior for manual alignment

How it works

The skill refactors module visibility by using private modules for implementation details and public re-exports for the API, while applying conditional compilation flags for testing and documentation.

Inputs & outputs

You give it
Rust module structure or mod.rs file
You get back
Organized module structure with re-exports and visibility controls

When to use organize-modules

  • Clean up mod.rs files in a Rust project
  • Expose public APIs while keeping internals private
  • Organize module visibility for unit testing

About this skill

Module Organization Best Practices

When to Use

  • Creating new Rust modules
  • Refactoring module structure
  • Organizing mod.rs files
  • Reviewing code that exposes internal structure
  • Making private types visible to documentation
  • Before creating commits with module changes
  • When user says "organize modules", "refactor modules", "fix module structure", etc.

Instructions

Follow these patterns for clean, maintainable module organization:

Step 1: Apply the Recommended Pattern

Prefer private modules with public re-exports (also known as the barrel export pattern) as the default pattern.

This provides a clean API while maintaining flexibility to refactor internal structure.

// mod.rs - Module coordinator

// Private modules (hide internal structure)
mod constants;
mod types;
mod helpers;

// Public re-exports (expose stable API)
pub use constants::*;
pub use types::*;
pub use helpers::*;

What this achieves:

  • Clean, flat API for users
  • Internal structure is hidden and can be refactored freely
  • No namespace pollution from module names

Step 2: Control Rustfmt Behavior (When Needed)

For mod.rs files with deliberate manual alignment, prevent rustfmt from reformatting:

// mod.rs

#![rustfmt::skip]

// Private modules
mod constants;
mod types;
mod helpers;

// Public re-exports
pub use constants::*;
pub use types::*;
pub use helpers::*;

When to use rustfmt skip:

  • Large mod.rs files with many exports
  • Deliberately structured code alignment for clarity
  • Manual grouping of related items (e.g., test fixtures)
  • Files where organization conveys semantic meaning

When NOT to use:

  • Small, simple mod.rs files
  • When automatic formatting is preferred

Step 3: Apply Conditional Visibility for Docs and Tests

When you need a module to be:

  • Private in production builds (encapsulation)
  • Public for documentation (rustdoc links work)
  • Public for tests (test code can access internals)

Use conditional compilation:

// mod.rs - Conditional visibility

#[cfg(any(test, doc))]
pub mod internal_parser;
#[cfg(not(any(test, doc)))]
mod internal_parser;

// Re-export items for the flat public API
pub use internal_parser::*;

How this works:

  • In doc builds: Module is public → rustdoc can see and link to it
  • In test builds: Module is public → tests can access internals
  • In production builds: Module is private → internal implementation detail

This pattern is frequently used with the write-documentation skill when fixing documentation links to private types.

When to Omit the Fallback Branch

You can skip the #[cfg(not(any(test, doc)))] fallback when the module has no code to compile in production:

// ✅ OK to skip fallback - documentation-only module (no actual code)
#[cfg(any(test, doc))]
pub mod integration_tests_docs;

// ✅ OK to skip fallback - all submodules are #[cfg(test)] anyway
#[cfg(any(test, doc))]
pub mod integration_tests;

Keep the fallback when the module contains code that must compile in production (even if private):

// ✅ Need fallback - module has actual code used in production
#[cfg(any(test, doc))]
pub mod internal_parser;
#[cfg(not(any(test, doc)))]
mod internal_parser;

pub use internal_parser::*;  // Re-exports need the module to exist!

Integration Tests Module

For modules that contain PTY integration tests (typically under integration_tests/), follow these rules:

  1. Dedicated Files: Each complex test gets its own file.
  2. Module Documentation: Use //! at the top of the file to document the test's intent.
  3. Run Instructions: Always include a "Run with:" section at the top of the file (see write-documentation skill for details).
  4. Conditional Visibility: Parent modules must make these test modules public for doc and test builds.
// integration_tests/mod.rs

#[cfg(any(test, doc))]
pub mod pty_feature_test;

Platform-Specific Modules with Cross-Platform Docs

For modules that are platform-specific but should have docs generated on all platforms, use any(doc, ...) to separate documentation from runtime requirements:

// ✅ Linux-only runtime, but docs build on all platforms
#[cfg(any(doc, all(target_os = "linux", test)))]
pub mod input;
#[cfg(all(target_os = "linux", not(any(test, doc))))]
mod input;

// Re-export also needs the doc condition
#[cfg(any(target_os = "linux", doc))]
pub use input::*;

Key insight: rustdoc runs the Rust compiler internally. When you write #[cfg(all(target_os = "linux", any(test, doc)))], the target_os = "linux" check still excludes macOS/Windows even during doc builds. The doc cfg flag doesn't override other conditions—it's just another flag you can check.

The fix: Use any(doc, ...) to make doc an alternative path:

  • any(doc, all(target_os = "linux", test)) means: "docs on any platform OR tests on Linux"
  • all(target_os = "linux", any(test, doc)) means: "Linux AND (tests OR docs)" — still requires Linux!

When you see broken doc links for platform-specific modules:

// ❌ Broken: Docs won't generate on macOS
#[cfg(all(target_os = "linux", any(test, doc)))]
pub mod linux_only_module;

// ✅ Fixed: Docs generate on all platforms (if module code is platform-agnostic)
#[cfg(any(doc, all(target_os = "linux", test)))]
pub mod linux_only_module;
#[cfg(all(target_os = "linux", not(any(test, doc))))]
mod linux_only_module;

⚠️ Unix Dependency Caveat

The cfg(any(doc, ...)) pattern above assumes the module's code compiles on all platforms. When the module uses Unix-only APIs (e.g., mio::unix::SourceFd, signal_hook, std::os::fd::AsRawFd), restrict doc builds to Unix:

// Module uses Unix-only APIs — restrict doc builds to Unix platforms
#[cfg(any(all(unix, doc), all(target_os = "linux", test)))]
pub mod input;
#[cfg(all(target_os = "linux", not(any(test, doc))))]
mod input;

#[cfg(any(target_os = "linux", all(unix, doc)))]
pub use input::*;

Three-tier hierarchy:

Module dependenciesPatternDocs: LinuxDocs: macOSDocs: Windows
Platform-agnosticcfg(any(doc, ...))
Unix APIscfg(any(all(unix, doc), ...))excluded
Linux-only APIscfg(any(all(target_os = "linux", doc), ...))excludedexcluded

Rule of thumb: Match your doc cfg guard to your dependency's cfg guard in Cargo.toml.

Apply at all levels — If the module is nested, both parent and child need the visibility change. Also update any re-exports:

// Parent module
#[cfg(any(doc, all(target_os = "linux", test)))]
pub mod integration_tests;

// Child modules inside integration_tests/mod.rs
#[cfg(any(doc, all(target_os = "linux", test)))]
pub mod pty_input_test;

// Re-exports
#[cfg(any(target_os = "linux", doc))]
pub use integration_tests::*;

Step 4: Handle Transitive Visibility

Important: If a conditionally public module links to another module in its documentation, that target module must also be conditionally public.

// mod.rs

#[cfg(any(test, doc))]
pub mod paint_impl;  // Contains docs that link to diff_chunks
#[cfg(not(any(test, doc)))]
mod paint_impl;

#[cfg(any(test, doc))]
pub mod diff_chunks;  // Must also be conditionally public!
#[cfg(not(any(test, doc)))]
mod diff_chunks;

// Re-export for public API
pub use paint_impl::*;
pub use diff_chunks::*;

Why: Rustdoc needs to resolve all links in documentation. If paint_impl docs link to diff_chunks, rustdoc must be able to see diff_chunks.

Step 5: Reference in Rustdoc

When linking to conditionally public modules in documentation, use the mod@ prefix:

/// See [`internal_parser`] for implementation details.
///
/// [`internal_parser`]: mod@crate::internal_parser

See the write-documentation skill for complete details on rustdoc links.

Step 6: Multi-Level Barrel Exports and Rustdoc Search

When rustdoc generates documentation, the search index includes all public items and modules. For multi-level barrel exports (pub mod intermediate; pub use intermediate::*;), the search index resolves the "shortest public path" for items. But rustdoc only generates HTML pages at the canonical definition path, not at the flattened re-export path.

This means searching for an item re-exported via a barrel might produce a link to a page that doesn't exist (e.g., core/ansi/csi/index.html instead of core/ansi/constants/csi/index.html).

The fix: Use #[doc(inline)] to re-export submodules at the parent level, but only when the intermediate module is a well-documented organizational hub (has module-level //! docs, organization tables, etc.) AND its submodules are pub mod.

Intermediate module characteristicsActionWhy
Public, has module docs, organization tablesAdd #[doc(inline)]Submodules are discoverable via search; pages must exist
Private with pub use *; only (pure barrel)No action neededSubmodules aren't in the search index at all
Public but no module docs (structural only)No action neededNot worth the doc noise; users won't search for these

In the parent module's mod.rs, add explicit #[doc(inline)] re-exports alongside the existing glob re-export:

// Existing: keeps flat item access working
pub use constants::*;

// New: creates rustdoc pages at th

---

*Content truncated.*

When not to use it

  • When the module structure is simple and does not require encapsulation
  • When automatic rustfmt formatting is preferred for all files

Limitations

  • Requires manual updates when adding new modules to the barrel export
  • Conditional visibility patterns can increase complexity in mod.rs files

How it compares

It provides a standardized pattern for managing Rust module visibility, preventing internal implementation details from leaking into the public API.

Compared to similar skills

organize-modules side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
organize-modules (this skill)12moReviewIntermediate
m06-error-handling16moReviewIntermediate
m04-zero-cost06moNo flagsIntermediate
m05-type-driven06moNo flagsAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry