Reader Locality
Definitions, decisions, and use sites kept near enough that a change does not require a repository tour.
91 items in this guidance cluster.
Tagged guidance
Guide items
Code Shapecode-shapeCode-shape guidance covers small source-level moves that reduce live context, improve reader locality, and keep structure changes reviewable. It focuses on local expression shape, cohesion, coupling, reversible structure, and separating behavior from preparation.Rust Maintainabilityrust-maintainabilityRust maintainability guidance applies the repos software-change preferences to Rust code, APIs, modules, errors, tests, dependencies, documentation, and release risk. It favors Rust that is easy to read locally, hard to misuse, and honest about public behavior.
Agent Workflow rules
Boundary rules
Identify Anemic State MachinesBOUNDARY-IDENTIFY-ANEMIC-STATE-MACHINESReplace scattered booleans and conditionals with named states and transitions when lifecycle behavior is already complex. The move exposes illegal transitions and missing recovery paths without over-formalizing simple linear code.Name Lifecycle TransitionsBOUNDARY-NAME-LIFECYCLE-TRANSITIONSModel creation, activation, cancellation, teardown, reload, and promotion as named operations when they carry different invariants. This keeps ordering, cleanup, retry, and recovery rules visible without adding ceremony to simple constructed values.Separate Pure Core From EffectsBOUNDARY-SEPARATE-PURE-CORE-FROM-EFFECTSMove domain computation away from rendering, I/O, mutation, and global state when effects obscure the decision being tested. The split gives tests a stable surface, but should be skipped when it adds indirection without a useful boundary.Separate UI And App StateBOUNDARY-SEPARATE-UI-AND-APP-STATEKeep selection, focus, scroll, expansion, and transient input mode separate from application-owned data when they change under different rules. The separation prevents rendering concerns from mutating domain state while allowing tiny tools to stay simple until friction appears.
Change Shape rules
Identify Owning Module Before EditingCHANGE-IDENTIFY-OWNING-MODULE-BEFORE-EDITINGFind the component that owns the concept before adding or moving logic. That keeps invariants, tests, and future maintenance close to the responsible code.Separate Structure From BehaviorCHANGE-SEPARATE-STRUCTURE-FROM-BEHAVIORSplit refactoring or layout changes from behavior changes when the combined diff obscures intent. Separate review units make meaning preservation and new behavior easier to check.Treat And as Scope WarningCHANGE-TREAT-AND-AS-SCOPE-WARNINGUse compound change descriptions as a prompt to inspect whether the work has more than one purpose. The word is not a rule, but it catches scope creep while splitting is still cheap.
Documentation rules
Avoid Generated Prose TellsDOCS-AVOID-GENERATED-PROSE-TELLSReplace templated, UI-centered, or polished-but-vague phrasing with concrete behavior. Keep the local voice trustworthy without cutting useful explanation.Choose Document TypeDOCS-CHOOSE-DOCUMENT-TYPEPick the dominant document mode before editing so the page serves one reader task well. Link out to secondary modes instead of blending tutorial, reference, decisions, and changelog.Front-Load Useful PointDOCS-FRONT-LOAD-USEFUL-POINTPut the decision, command, invariant, or warning before broad setup. Readers and agents can then use the page without hunting through introductory prose.Group Related List ItemsDOCS-GROUP-RELATED-LIST-ITEMSCluster long lists under useful names when the relationships matter. Keep short or causal material flat or in prose so structure does not add noise.Hide Catalog MechanicsDOCS-HIDE-CATALOG-MECHANICSLead user-facing copy with work areas, artifacts, and destinations instead of IDs or generated structure. Mention catalog mechanics only when citation or contribution work needs them.Match Page Shape to Reader TaskDOCS-MATCH-PAGE-SHAPE-TO-READER-TASKShape pages around the readers task, such as learning, choosing, reference, or review. The right structure lowers scan cost without forcing one page to do every job.Name Destination, Not DirectionDOCS-NAME-DESTINATION-NOT-DIRECTIONUse labels that name the section, object, or decision the reader will reach. Directional labels make readers follow the page order before knowing whether it is relevant.One Dominant Mode per PageDOCS-ONE-DOMINANT-MODE-PER-PAGELet each page have one primary mode and move competing material behind links. This keeps readers from paying for tutorial, reference, explanation, and policy at once.Own AI-Assisted ProseDOCS-OWN-AI-ASSISTED-PROSEAI-generated or AI-assisted docs are reasonable to share when human curation makes them author-owned. The published artifact should carry checked claims, reader-sized scope, relevant evidence, real tradeoffs, and local voice.Prose for Relationships, Lists for EnumerationDOCS-PROSE-FOR-RELATIONSHIPS-LISTS-FOR-ENUMERATIONUse prose when causality, contrast, or priority matters, and lists when enumerating parallel items. The shape should reveal the relationship instead of hiding it in bullets.README as Entry PointDOCS-README-AS-ENTRY-POINTUse README files to orient readers to purpose, setup, first useful use, and deeper docs. Split out manual-level detail when it hides the starting path.Separate Technique From Example PolicyDOCS-SEPARATE-TECHNIQUE-FROM-EXAMPLE-POLICYTraining examples should distinguish the library or framework technique being taught from application-specific policy. Explain the policys rationale, tradeoffs, and meaningful edge cases, then tell readers what to reuse and what to reconsider.Use Concrete DetailsDOCS-USE-CONCRETE-DETAILSName real commands, paths, defaults, types, examples, and work areas when they clarify scope. Concrete detail removes guesswork without overloading prose with incidental facts.Use Descriptive HeadingsDOCS-USE-DESCRIPTIVE-HEADINGSWrite headings that name the section content, destination, or decision area. Reserve imperative headings for procedures where the section is truly a step.Write for Non-Linear ReadersDOCS-WRITE-FOR-NON-LINEAR-READERSGive sections enough local context to work when reached from search, links, review, or retrieval. Avoid repeating the whole introduction; add only the subject and prerequisite needed.Write Technical ProseDOCS-WRITE-TECHNICAL-PROSEUse direct technical language that carries contracts, commands, evidence, and tradeoffs. Cut marketing, coaching, chat, and page narration when they do not explain the system.
Refactoring rules
Do Not Over-apply DRYREFACTORING-DO-NOT-OVER-APPLY-DRYKeep similar-looking code separate until it has the same meaning and changes together. Premature sharing can couple unrelated policies and make later edits harder.Extract Concept HelpersREFACTORING-EXTRACT-CONCEPT-HELPERSExtract helpers when the new function names a real concept boundary with a stable purpose. Hiding a few lines behind a weak name adds a jump without reducing the readers burden.Keep Linear Story VisibleREFACTORING-KEEP-LINEAR-STORY-VISIBLEKeep simple ordered workflows inline when the sequence is the clearest explanation. Extract only the substeps that carry their own concept, policy, reuse, or test surface.Keep Weak Abstractions CloseREFACTORING-KEEP-WEAK-ABSTRACTIONS-CLOSE-TO-THEIR-USEKeep tentative helpers, types, or traits near their first use until the boundary proves itself. Local placement makes weak abstractions easier to revise, inline, or delete before other modules depend on them.Make Edge Cases ExplicitREFACTORING-MAKE-EDGE-CASES-EXPLICITName boundary behavior near the branch, calculation, or return that depends on it. This makes policy reviewable and shows when stronger types should prevent invalid states instead.Prefer Local ReasoningREFACTORING-PREFER-LOCAL-REASONINGShape code so relevant state, invariants, and effects are visible near the change. Centralize only when it reduces total reasoning, because distant reconstruction raises cognitive load and error risk.Prefer Loops for Side EffectsREFACTORING-PREFER-LOOPS-FOR-SIDE-EFFECTSUse ordinary loops when the main purpose is mutation, I/O, logging, or other side effects. Iterator chains are better for value transformation; using them for effects can hide order, early exits, and error handling.Use Whitespace as Function ParagraphsREFACTORING-USE-WHITESPACE-AS-FUNCTION-PARAGRAPHSUse blank lines to group related statements inside a function before extracting more names. Paragraph-like spacing can reveal the local story while avoiding unnecessary helper jumps.
Review rules
Classify Prototype ReuseREVIEW-CLASSIFY-PROTOTYPE-REUSEClassify whether a rebuild is reusing behavior, evidence, replaceable internal shape, or load-bearing boundaries. That separation helps preserve proven compatibility while discarding prototype scaffolding.Preserve Durable Answers Near SourceREVIEW-EXPLAIN-CONTROVERSIAL-CHOICES-INLINETreat capable reviewer questions about non-obvious code as documentation signals. Preserve the durable answer at the closest appropriate source boundary so future readers do not have to rediscover it.
Rust rules
Avoid Broad Context and CallbacksRUST-AVOID-BROAD-CONTEXT-AND-CALLBACKSPass explicit inputs and keep control flow local instead of hiding it in context bags or callbacks. This makes ownership, effects, and ordering easier to audit.Avoid Empty Wrapper TypesRUST-AVOID-EMPTY-WRAPPER-TYPESAdd a wrapper type only when it carries an invariant, behavior, or ownership boundary. Otherwise it adds conversions and concepts without improving correctness.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 Inline ModulesRUST-AVOID-INLINE-MODULESPut nontrivial modules in named files unless tests, preludes, or generated code justify inline layout. Stable paths make search, review, and ownership clearer.Avoid mod.rs by DefaultRUST-AVOID-MOD-RS-BY-DEFAULTPrefer named module files when they make tabs, paths, and search results clearer. Reserve mod.rs for cases where local convention or layout makes it the better signal.Avoid Overcommenting Trivial CodeRUST-AVOID-OVERCOMMENTING-TRIVIAL-CODEComment Rust code for invariants, contracts, and surprising tradeoffs rather than restating obvious operations. This keeps comments useful and less prone to drift.Avoid Path AttributesRUST-AVOID-PATH-ATTRIBUTEUse normal Rust module lookup unless generated or platform-specific layout needs #[path]. Predictable file paths make navigation and ownership easier to infer.Avoid Tiny Module MazesRUST-AVOID-TINY-MODULE-MAZESKeep small helper code near its use unless a separate module owns a real concept. This reduces file-jumping and preserves reader locality.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.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 Module ImportsRUST-GROUP-MODULE-IMPORTSGroup related imports by module when that matches local style. This makes dependency shape easier to scan and avoids churn from one-import-per-line edits.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.Keep Concepts CoherentRUST-KEEP-CONCEPTS-COHERENTGive each module, type, or helper one recognizable idea to own. Coherent ownership keeps readers from carrying unrelated parsing, state, rendering, and policy facts at once.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.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.Make Side Effects ExplicitRUST-MAKE-SIDE-EFFECTS-EXPLICITPut mutation, I/O, registration, cleanup, and background work in names, call sites, or docs when callers must account for them. Keep tiny private helpers plain when the surrounding code already makes the effect obvious.Name Auditable IntermediatesRUST-NAME-AUDITABLE-INTERMEDIATESIntroduce named locals where parsing, validation, rendering, ownership, or side-effect decisions need review. Avoid naming every trivial expression when it would add ceremony without clarifying the boundary.Order Code For ReadingRUST-ORDER-CODE-FOR-READINGArrange code so central items, callers, or public API appear before supporting helpers when that makes the file readable top to bottom. Prefer the order that reduces reader jumping over mechanical rearrangement.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 Boring Direct CodeRUST-PREFER-BORING-DIRECT-CODEPrefer explicit Rust control flow, types, and error handling over clever framework-shaped indirection. Use macros or abstractions when they remove real repetition or enforce real invariants.Prefer Concept Owned Modules And Named FilesRUST-PREFER-CONCEPT-OWNED-MODULES-AND-NAMED-FILESOrganize modules around domain concepts and give important concepts named files that own their types, invariants, tests, and docs. Use infrastructure modules only when the cross-cutting concept is real and bounded.Prefer Small Clear ShapesRUST-PREFER-SMALL-CLEAR-SHAPESFavor small functions, narrow structs, and simple enums that keep live facts local for readers. Do not split cohesive logic into fragments that force more navigation than understanding.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.Review As Future MaintainerRUST-REVIEW-AS-FUTURE-MAINTAINERReview Rust changes for the reader who will debug, extend, or release the code later, not only for immediate correctness. Favor maintainable API shape, docs, tests, and error behavior over changes that merely compile.Shape Expressions For AuditabilityRUST-SHAPE-EXPRESSIONS-FOR-AUDITABILITYShape complex expressions so ownership, validation, error handling, and side effects can be audited at the point they occur. Break chains or introduce names when density hides a decision readers must verify.Use Directory Modules As Tables Of ContentsRUST-USE-DIRECTORY-MODULES-AS-TABLES-OF-CONTENTSLet directory module files introduce, organize, and re-export the concepts owned by that directory. Keep substantial implementation in named child files so the module remains a readable table of contents.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 Field Init ShorthandRUST-USE-FIELD-INIT-SHORTHANDUse field init shorthand when variable names already match struct fields so initialization stays compact and familiar. Spell fields out when renaming, conversion, or policy deserves visible attention.Use Functions For Incidental TypesRUST-USE-FUNCTIONS-FOR-INCIDENTAL-TYPESPrefer free or module functions when a type does not own the operation or invariant. Move behavior onto a type when the method relationship clarifies state, policy, or trait design.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.
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.Cap Change Radiuscap-change-radiusBroad diffs increase review cost and make unrelated regressions harder to isolate. Keep the change radius aligned with the requested behavior, using separate chunks for cleanup or adjacent improvements.Chunk Statementschunk-statementsDense prose asks readers to hold too many claims at once and hides which idea needs review. Split statements into coherent chunks so each paragraph, bullet, or sentence carries one inspectable purpose.Delete Redundant Commentsdelete-redundant-commentsComments that repeat obvious code add reading burden and become stale faster than the behavior they describe. Remove them or replace them with context that explains intent, invariant, risk, or non-obvious tradeoff.Keep Name Currentkeep-name-currentNames that preserve old intent make readers distrust the code or documentation around them. Rename when the concept changes enough that the old name now teaches the wrong model.Keep Structure Reversiblekeep-structure-reversibleEarly structure can harden into unnecessary abstraction before the design is proven. Prefer arrangements that are easy to inline, split, merge, or rename until the underlying concept earns permanence.Limit Live Contextlimit-live-contextReaders make mistakes when they must keep too many facts active to understand a change. Reduce live context by moving related facts together, naming intermediate concepts, and keeping dependencies local.Make Parameters Explicitmake-parameters-explicitHidden configuration, time, randomness, globals, or environment reads make behavior hard to reason about and test. Gather ambient data at the outer boundary, then pass typed inputs or a cohesive context to the inner operation.Make State Transitions Explicitmake-state-transitions-explicitLifecycle rules become fragile when status fields, timestamps, events, and validation checks are coordinated by hand. Give meaningful transitions a named owner that holds the preconditions, state update, event, and error behavior together.Move Declaration And Initialization Togethermove-declaration-and-initialization-togetherA value declared before it is valid makes readers track an empty slot and its future assignment. Declare values where they become meaningful, using immutable locals and narrow scopes unless evaluation order requires more care.Name Couplingname-couplingRelationships between pieces are hard to judge when the reason they change together is unnamed. Describe the change pressure first, then decide whether the coupling belongs directly, behind a clearer owner, or across an explicit boundary.Optimize For Agent Legibilityoptimize-for-agent-legibilityRepositories that are hard for agents to inspect, search, run, and validate make delegated work slower and less reliable. Prefer structures, commands, names, examples, and runtime signals that help both agents and human maintainers reason locally.Optimize For Long Term Coherenceoptimize-for-long-term-coherenceAgent-produced work can satisfy a prompt while weakening the systems future concepts, names, boundaries, and tests. Choose the smallest change that preserves long-term direction without using coherence as an excuse for speculative architecture.Reader Localityreader-localityA change can reduce code size while increasing the number of jumps needed to understand one workflow. Keep related concepts near their meaning, extracting only when the new name and location reduce live context.Run Source Explanation Passrun-source-explanation-passTurn a source tree into a self-contained reading environment by recovering its mental models, fundamentals, decisions, constraints, and edge cases. Establish the system map before item detail, audit every relevant helper and path, and measure success through reader comprehension rather than comment count.Separate Structure From Behaviorseparate-structure-from-behaviorDiffs that mix moves, renames, formatting, and behavior make review and rollback harder. Separate behavior-preserving structure from rule changes when each can be checked on its own.Strengthen Cohesionstrengthen-cohesionA concept becomes harder to understand when its data, rules, and behavior are scattered or bundled with unrelated concerns. Move elements that change for the same reason toward one named owner, while separating nearby code that belongs to another concept.Untangle Before Changinguntangle-before-changingBehavior changes become risky when policy, formatting, validation, persistence, and side effects are braided together. Untangle only enough structure to give the new behavior a clear owner, then keep the behavior change reviewable.Use Explaining Variableuse-explaining-variableImportant decisions disappear when nested expressions or repeated conditions expose syntax before domain meaning. Introduce a local name when it makes the next branch, call, or return read in terms of the fact the reader needs.Use Guard Clauseuse-guard-clauseThe normal path is harder to see when the rest of a routine is indented under a precondition or failure case. Exit early for boring gates so the ordinary behavior stays flat, visible, and ordered by what readers must rule out.