Public API

Interfaces and behavior that callers may depend on across a crate or system boundary.

70 items in this guidance cluster.

Tagged guidance

Guide item

Agent Workflow rules

Boundary rules

Choose Resource Identity ModelBOUNDARY-CHOOSE-RESOURCE-IDENTITY-MODELDecide whether the boundary mutates records, sets, files, sessions, handles, or whole documents before designing reconciliation. The chosen unit controls idempotency, matching, conflict handling, and the cost of later migration.Ground Integrations In Primary SourcesBOUNDARY-GROUND-INTEGRATIONS-IN-PRIMARY-SOURCESBase adapter behavior on provider docs, specs, or captured API responses before encoding local assumptions. When primary sources are incomplete, label observations and inferences so guesses do not become fake guarantees.Keep Backend Adapters At EdgeBOUNDARY-KEEP-BACKEND-ADAPTERS-AT-EDGEKeep provider-specific terminal, storage, network, and runtime APIs in adapter layers at the boundary. Core logic stays stable and testable while real backend differences remain modeled instead of hidden behind a false common API.Model Real Upstream SurfaceBOUNDARY-MODEL-REAL-UPSTREAM-SURFACEShape local integration APIs around the providers actual records, pages, permissions, rate limits, and consistency behavior. Wrappers may simplify common paths, but they should not promise capabilities the upstream cannot provide.Reject Unsupported ShapesBOUNDARY-REJECT-UNSUPPORTED-SHAPESFail unsupported names, values, TTLs, targets, record families, protocols, or modes at the boundary with clear errors. Preserve unknown data only when compatibility requires round-tripping and the system can do so safely.

Change Shape rules

Documentation rules

Rust rules

Avoid Giant Crate RootsRUST-AVOID-GIANT-CRATE-ROOTSUse the crate root to teach the public shape and route readers to focused modules. This keeps lib.rs or main.rs from becoming the whole implementation surface.Avoid Glob Re-ExportsRUST-AVOID-GLOB-REEXPORTSRe-export public facade names explicitly instead of using globs. This prevents accidental API expansion and makes exported names visible during review.Avoid Public Dependency CouplingRUST-AVOID-PUBLIC-DEPENDENCY-COUPLINGKeep dependency types out of public APIs unless interoperability is the purpose. This preserves semver freedom and avoids forcing downstream users onto implementation choices.Central Item FirstRUST-CENTRAL-ITEM-FIRSTPut the main type, trait, enum, or function before supporting details. Readers can learn the modules purpose before chasing helpers and adapters.Choose Generics and Trait Objects DeliberatelyRUST-CHOOSE-GENERICS-AND-TRAIT-OBJECTS-DELIBERATELYPick generics, stored type parameters, or trait objects for the variation they actually model. The choice affects compile cost, object safety, lifetimes, and caller ergonomics.Consider Downstream API ImpactRUST-CONSIDER-DOWNSTREAM-API-IMPACTCheck public API changes against downstream imports, traits, inference, and examples before reshaping them. Additive paths and deprecations often avoid unnecessary breakage.Do Not Default pub(crate)RUST-DO-NOT-DEFAULT-PUB-CRATEStart items private and widen to pub(crate) only for deliberate shared internals. This keeps modules independent and makes crate-local contracts visible.Do Not Pin Patch VersionsRUST-DO-NOT-PIN-PATCH-VERSIONSKeep manifest requirements as wide as the crate honestly supports. Patch pins belong in Cargo.toml only when code depends on that patchs API, fix, or behavior.Document Current Implemented BehaviorRUST-DOCUMENT-CURRENT-IMPLEMENTED-BEHAVIORDocument what the crate does today instead of presenting future plans as available contract. Clear tense and labels prevent callers from relying on unimplemented behavior.Document Feature ContractsRUST-DOCUMENT-FEATURE-CONTRACTSExplain what each feature flag enables, requires, and promises. Feature contracts help users choose combinations without guessing from dependency names.Document Performance ContractsRUST-DOCUMENT-PERFORMANCE-CONTRACTSState meaningful performance expectations when callers may design around them. Clear limits keep complexity and optimization claims tied to supported behavior.Document Visibility OwnershipRUST-DOCUMENT-VISIBILITY-OWNERSHIPPair widened visibility with names and docs that identify the owning concept. This prevents shared internals from looking like accidental stable API.Expose Primary Path from Crate RootRUST-EXPOSE-PRIMARY-PATH-FROM-CRATE-ROOTMake the crate root show the main workflow, types, and import path. Users should not have to infer the intended entry point from private layout details.Group Private Imports Before Public Re-ExportsRUST-GROUP-PRIVATE-IMPORTS-BEFORE-PUBLIC-RE-EXPORTSSeparate implementation imports from public re-exports in module prologues. The grouping lets readers distinguish internal dependencies from the API surface being presented.Hide Test-Only HelpersRUST-HIDE-TEST-ONLY-HELPERSKeep fixtures and shortcuts behind test-only modules, features, or support crates unless they are deliberate API. This prevents scaffolding from leaking into production contracts.Implement Debug for Public TypesRUST-IMPLEMENT-DEBUG-FOR-PUBLIC-TYPESProvide Debug for public types unless it would expose secrets or mislead callers. The trait is baseline support for tests, assertions, logs, and downstream diagnostics.Implement Standard Traits for Public ErrorsRUST-IMPLEMENT-STANDARD-TRAITS-FOR-PUBLIC-ERRORSMake reusable public errors implement the standard diagnostic traits where appropriate. This lets callers compose, display, chain, and inspect errors in ordinary Rust workflows.Keep Crate Boundaries NarrowRUST-KEEP-CRATE-BOUNDARIES-NARROWPut behavior and tests in the crate or module that owns them before extracting shared helpers. Narrow boundaries reduce dependency fan-out, feature pressure, and hidden coupling.Keep Pre-Release Compatibility IntentionalRUST-KEEP-PRE-RELEASE-COMPATIBILITY-INTENTIONALPreserve pre-release compatibility only when it reflects a chosen contract. Early cleanup is often cheaper than freezing accidental names, re-exports, features, or variants.Keep Preludes Re-Export OnlyRUST-KEEP-PRELUDES-REEXPORT-ONLYPut only re-exports in prelude modules and keep original behavior in its owning module. Users expect preludes to aid imports, not hide implementation ownership.Keep Public API Shape IntentionalRUST-KEEP-PUBLIC-API-SHAPE-INTENTIONALMake public visibility, aliases, features, re-exports, bounds, and variants reflect intended commitments. Published surface area becomes something downstream users can depend on.Make Feature Flags Additive Where PossibleRUST-MAKE-FEATURE-FLAGS-ADDITIVE-WHERE-POSSIBLEDesign feature flags as additive capabilities whenever possible so Cargo feature unification does not surprise downstream builds. Make incompatible combinations explicit when addition cannot model the real choice.Make Public API Browseable From LayoutRUST-MAKE-PUBLIC-API-BROWSEABLE-FROM-LAYOUTAlign public modules, re-exports, and source files so readers can navigate from API to ownership without translation. Facades are fine when they improve discovery and still point toward the owning concept.Non Exhaustive Public ErrorsRUST-NON-EXHAUSTIVE-PUBLIC-ERRORSMark public error enums non-exhaustive unless exhaustive matching is part of the contract. This preserves room for future integration, validation, or provider failures without needless downstream breakage.Order Items For API ReadingRUST-ORDER-ITEMS-FOR-API-READINGOrder imports, public items, impls, trait impls, and helpers so the API story is easy to scan. Respect macros, generated code, and local convention when another order communicates better.Prefer Constructors And Conversion TraitsRUST-PREFER-CONSTRUCTORS-AND-CONVERSION-TRAITSUse inherent constructors and standard conversion traits to show whether construction builds, validates, converts, borrows, allocates, or can fail. Prefer public fields only when direct construction is truly part of the contract.Reexport For DiscoveryRUST-REEXPORT-FOR-DISCOVERYRe-export public items where callers naturally look so the crate surface is discoverable without hiding ownership. Keep canonical definitions and docs clear so re-exports do not become competing homes.Teach Crate From Crate RootRUST-TEACH-CRATE-FROM-CRATE-ROOTUse crate-root docs and exports to teach the crates main concepts, entry points, and common paths. Keep the root focused enough to orient readers without duplicating every item-level contract.Tie Optional Dependencies To Named FeaturesRUST-TIE-OPTIONAL-DEPENDENCIES-TO-NAMED-FEATURESConnect optional dependencies to clear feature names that explain the capability callers enable. Avoid leaking dependency names as the public feature design when the capability needs a more stable contract.Use Builders For Optional Or Validated FieldsRUST-USE-BUILDERS-FOR-OPTIONAL-OR-VALIDATED-FIELDSUse builders when construction has many optional inputs or cross-field validation that would make constructors hard to read. Avoid builder APIs for simple values where direct construction communicates the contract better.Use Doc Inline For Canonical ReexportsRUST-USE-DOC-INLINE-FOR-CANONICAL-REEXPORTSUse #[doc(inline)] when a re-export should be the canonical place readers encounter an item. Avoid inlining re-exports that would obscure the owning module or create duplicate-looking documentation.Use Honest Minimum DependenciesRUST-USE-HONEST-MINIMUM-DEPENDENCIESSet dependency requirements to the lowest compatible versions the crate actually supports. Raise minimums only for required APIs, fixes, features, security needs, or MSRV interactions.Use Meaningful Standard TypesRUST-USE-MEANINGFUL-STANDARD-TYPESPrefer standard or ecosystem types that encode ownership, units, paths, durations, optionality, and invariants better than raw strings or integers. Use domain newtypes when the standard type cannot prevent meaningful mixups.Use Send Static Across TasksRUST-USE-SEND-STATIC-ACROSS-TASKSRequire owned Send + static values, futures, errors, and handles when they cross spawn or thread boundaries. Avoid imposing those bounds on local synchronous APIs where they would reject valid use.Validate Semver Breaks Against External UseRUST-VALIDATE-SEMVER-BREAKS-AGAINST-EXTERNAL-USECheck semver-breaking changes against real examples, dependents, or migration paths before treating an API cleanup as cheap. External evidence informs the cost even when security, soundness, or design repair still justify the break.Write Public Docs For Caller TasksRUST-WRITE-PUBLIC-DOCS-FOR-CALLER-TASKSWrite public Rustdoc around what callers are trying to decide, do, and rely on. Start with concise behavior and add arguments, failures, lifecycle, features, links, or examples only when they help the task.Write Rustdoc As API ContractRUST-WRITE-RUSTDOC-AS-API-CONTRACTUse Rustdoc to state caller-facing behavior, invariants, failures, side effects, and compatibility promises. Leave private implementation detail in comments unless it helps maintain the public contract.

Source rules

Testing rules

Pattern items

Avoid Boolean Flag Parametersavoid-boolean-flag-parametersBehavioral boolean flags make call sites depend on hidden ordering and branch semantics. Distinguish them from boolean domain data, then prefer named operations, enums, options types, or builders when the caller selects behavior.Document Errors Panics Safetydocument-errors-panics-safetyCallers need to know which failures are recoverable, which conditions panic, and what safety obligations an API imposes. Document those contracts at the public boundary so users can compose the API deliberately.Keep Public Dependencies Intentionalkeep-public-dependencies-intentionalPublic dependencies shape downstream compatibility, API expectations, and maintenance cost. Add or raise them only when the public behavior needs that requirement, using lockfile updates for ordinary compatible refreshes.Make Invalid States Hard To Expressmake-invalid-states-hard-to-expressRepeated validation spreads invariants across callers and lets unchecked values travel too far. Move the rule into a construction boundary or precise type when that reduces downstream reasoning without adding local ceremony.Parse Dont Validateparse-dont-validateValidation that returns raw values forces callers to remember which invariants already hold. Parse uncertain input into types that carry those invariants, using constructors or standard parsing traits that honestly match the boundary.Prefer Standard Conversionsprefer-standard-conversionsProject-specific conversion names make APIs harder to predict when standard traits already describe the relationship. Use standard conversions only when their semantics are honest, and choose explicit domain methods for lossy, contextual, or surprising operations.Return Structured Errorsreturn-structured-errorsString-only errors hide the stable facts callers need for branching, retrying, logging, and support. Return structured error values with machine-readable kinds and context, then render audience-specific messages at the boundary.Run Rustdoc Quality Passrun-rustdoc-quality-passUse a bounded checklist when raising a Rust crates public documentation. The pass should teach the crate model, document public contracts, place examples where they prove real use, keep documentation layers aligned, and validate Rustdoc as code.Write Actionable Error Messageswrite-actionable-error-messagesAccurate error messages can still leave users, operators, callers, or support unable to act. Design failure output so the audience can find the attempted operation, affected item, known cause, impact, next step, and diagnostic handle when those facts matter.Write Docs As Contractswrite-docs-as-contractsBehavior and obligations become surprising when they are only discoverable by reading implementation details. Treat docs as part of the change surface, updating contracts and rationale alongside the code they describe.

Principle items

Mechanism item

Agent item