agentleFS
uwuclxdyuwuclxdy/agenticat/skills/clean-code/SKILL.md

clean-code

Skill7 starsChanged 17 days agoMITView on GitHub

Language-agnostic clean-code baseline: naming, functions, error handling, comments, duplication.

108 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use intelligent-routing, nextjs-react-expert and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • SKB3002Skill

    intelligent-routing

    Automatic agent selection and intelligent task routing. Analyzes user requests and automatically selects the best specialist agent(s) without requiring explicit user mentions.

    Also in 5 projects that use this

  • SKB3002Skill

    nextjs-react-expert

    React and Next.js performance optimization from Vercel Engineering. Use when building React components, optimizing performance, eliminating waterfalls, reducing bundle size, reviewing code for performance issues, or implementing server/client-side optimizations.

    Also in 3 projects that use this

  • xfstudioSkill

    bash-pro

    Master of defensive Bash scripting for production automation, CI/CD

    Also in 4 projects that use this

  • xfstudioSkill

    code-refactoring-tech-debt

    You are a technical debt expert specializing in identifying, quantifying, and prioritizing technical debt in software projects. Analyze the codebase to uncover debt, assess its impact, and create acti

    Also in 4 projects that use this

  • flying-diceSkill

    clean-code-review

    Multi-agent clean code audit — each principle gets its own agent

    Also in 3 projects that use this

  • goca-seSkill

    batch-operations

    Apply a change safely across many files — refactors touching more than 5 files, library or API migrations, project-wide renames of symbols/imports/paths, or adding boilerplate to many files. Use when "do it all at once" risks context overflow or silent failures.

    Also in 3 projects that use this

  • +4 more from xfstudio

The file

Show its rules and text

We split this skill into the rules it gives an agent

49 rules. 0 are common, 32 are distinctive, and 17 are very specific to this project.

  • 0

    Common

    Most of the 101 edited versions we read keep these.

  • 32

    Distinctive

    This author's own choices. Worth a look.

  • 17

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use these when you write, review, or refactor code.

    line 12
  2. Distinctive:

    Treat these as directional principles.

    line 14
  3. Distinctive:

    Never use variable names that create false expectations, contain misleading technical terms, or use visually confusing characters.

    line 22
  4. Very specific:

    Use names that honestly reflect the data structure (accountsMap, accountsGroup).

    line 25
  5. Distinctive:

    Use distinct names for classes/variables so autocomplete doesn't trick you.

    line 26
  6. Very specific:

    Create names that vary in tiny ways (e.g., ABCManagerForEfficientProcessingOfUsers vs ...PersistingOfUsers).

    line 30
  7. Very specific:

    Use characters that look identical (lowercase l vs 1, uppercase O vs 0).

    line 31
  8. Distinctive:

    If two things have different names, they must do different things.

    line 36
  9. Very specific:

    Use specific, role-based names for classes (e.g., OrderValidator, OrderRepository, OrderCalculator).

    line 40
  10. Very specific:

    Add meaningless noise suffixes when you can't think of a better name (e.g., OrderManager, OrderHandler, OrderController, OrderProcessor all …

    line 43
  11. Distinctive:

    Use real words that describe intent.

    line 50
  12. Very specific:

    Use single letters (i, j) only in tiny scopes, like a short for loop.

    line 52
  13. Very specific:

    Use single letters in larger scopes (searching for e returns thousands of useless hits).

    line 56
  14. Very specific:

    Use an abbreviation that reads fine but decodes several ways: in const tx = t[i], is tx time, tax, text, or transaction?

    line 57
  15. Distinctive:

    Do not encode type or scope information into variable names.

    line 61
  16. Very specific:

    Use names that describe intent, with no type prefixes: let firstName: string.

    line 64
  17. Very specific:

    Use "Hungarian Notation" to prefix variables with their type: let strFirstName: string.

    line 67
  18. Very specific:

    Write a comment above a complex if statement to explain what it does.

    line 84
  19. Distinctive:

    Write long functions that mix high-level conditions with low-level math and nested loops.

    line 100
  20. Very specific:

    Test your functions: if you can label sections with comments like // Validation, // Storage, // Notification, extract each into its own …

    line 107
  21. Very specific:

    Test your extractions: if extracting a function produces a name that merely restates its body (e.g., uploadBasedOnSize), the ORIGINAL …

    line 108
  22. Distinctive:

    Write "micromanager" functions that handle validation, calculation, database storage, and email notifications all at once.

    line 111
  23. Distinctive:

    Keep every line at one level of abstraction, delegating deeper detail one level down.

    line 118
  24. Distinctive:

    Ensure functions only do what their names say.

    line 149
  25. Very specific:

    Use try/catch for a clean list of steps.

    line 181
  26. Distinctive:

    Use data structures with separate procedure classes when new functions arrive frequently.

    line 228
  27. Distinctive:

    Keep a pass-through: if deleting the module makes complexity vanish, delete it, unless something varies across it or it is a migration shim.

    line 253
  28. Distinctive:

    Test past the interface; wanting to usually means the module has the wrong shape.

    line 254
  29. Distinctive:

    Avoid comments that explain what code does, since they eventually rot into outdated lies.

    line 262
  30. Distinctive:

    Write code so clear it doesn't need comments.

    line 265
  31. Very specific:

    Document public APIs with the language's doc-comment format (/// rustdoc, / */ JSDoc): the public surface is the one place comments earn …

    line 270
  32. Distinctive:

    Write comments explaining basic code behavior.

    line 273
  33. Distinctive:

    Leave old comments behind when refactoring logic.

    line 274
  34. Distinctive:

    Write "mumbling" comments that lack context.

    line 276
  35. Distinctive:

    Never use comments to store old code, authorship, or history logs.

    line 287
  36. Distinctive:

    Delete commented-out code entirely.

    line 290
  37. Distinctive:

    Write clean, small functions that do one thing, so you don't need comments to track where blocks end.

    line 292
  38. Distinctive:

    Leave half-dead commented code in your files.

    line 303
  39. Very specific:

    Keep authorship tags (e.g., // Created by John Doe - March 2019).

    line 304
  40. Very specific:

    Keep journal logs, closing-brace labels, or section markers (// 11-Oct-2001: Renamed getUserInfo..., } // end outer for loop, // ======== …

    line 305
  41. Distinctive:

    Place your highest-level function at the top of the file.

    line 316
  42. Distinctive:

    Place every supporting function just below its caller.

    line 317
  43. Distinctive:

    Use blank lines to separate distinct concepts.

    line 326
  44. Distinctive:

    Use a blank line to indicate a new concept is starting.

    line 329
  45. Distinctive:

    Keep related lines of code tightly grouped together (vertically dense).

    line 330
  46. Distinctive:

    Use proper indentation for each scope level.

    line 331
  47. Distinctive:

    Write walls of text with no spacing, or blank lines between every single line (both hide the hierarchy).

    line 334
  48. Distinctive:

    Keep shared class properties in one designated place (usually the top of the class).

    line 342
  49. Distinctive:

    Follow the team's calls on tabs vs.

    line 343

“Common” is measured: kept by at least 6 in 10 of the 101 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Clean Code Principles

Use these when you write, review, or refactor code.

Treat these as directional principles. Where a repo's established precedent or a language's own idioms conflict with a rule here, follow the local convention and match the surrounding code.


1. Naming & Readability

1.1 Avoid Disinformation

Never use variable names that create false expectations, contain misleading technical terms, or use visually confusing characters.

Do:

  • Use names that honestly reflect the data structure (accountsMap, accountsGroup).
  • Use distinct names for classes/variables so autocomplete doesn't trick you.

Don't:

  • Name a map accountList just because it holds several items; to a programmer "list" means an indexed structure.
  • Create names that vary in tiny ways (e.g., ABCManagerForEfficientProcessingOfUsers vs ...PersistingOfUsers).
  • Use characters that look identical (lowercase l vs 1, uppercase O vs 0).
    • Bad: int a = l; if (O == l) a = O1; else l = O1;

1.2 Make Meaningful Distinctions

If two things have different names, they must do different things. Avoid meaningless noise words and number series.

Do:

  • Reveal the actual role of variables (e.g., array, condition, transformation).
  • Use specific, role-based names for classes (e.g., OrderValidator, OrderRepository, OrderCalculator).

Don't:

  • Add meaningless noise suffixes when you can't think of a better name (e.g., OrderManager, OrderHandler, OrderController, OrderProcessor all existing side by side).

1.3 Use Searchable, Pronounceable Names

Names should read as natural words and match the size of their scope, so they can be spoken aloud and found by search. Avoid cryptic abbreviations, single letters outside tiny scopes, and raw magic numbers.

Do:

  • Use real words that describe intent.
    • Good: let generationTimestamp = new Date();
  • Use single letters (i, j) only in tiny scopes, like a short for loop.

Don't:

  • Mash abbreviations into cryptic strings.
  • Use single letters in larger scopes (searching for e returns thousands of useless hits).
  • Use an abbreviation that reads fine but decodes several ways: in const tx = t[i], is tx time, tax, text, or transaction? A pronounceable, searchable name can still force the reader to keep a lookup table in their head.

1.4 Avoid Encodings (Hungarian Notation)

Do not encode type or scope information into variable names. Let your IDE and compiler handle types.

Do:

  • Use names that describe intent, with no type prefixes: let firstName: string;

Don't:

  • Use "Hungarian Notation" to prefix variables with their type: let strFirstName: string;

1.5 Expressive Logic (Self-Documenting Code)

Refactor complex logic into well-named variables, functions, constants. The code then explains itself without comments.

Do:

  • Extract complex conditions into well-named boolean variables.
    • Good:
      const isBusinessHour = currentHour >= OPENING_HOUR && currentHour < CLOSING_HOUR;
      const isBusinessDay = currentDay !== SATURDAY && currentDay !== SUNDAY;
      const isStoreOpen = isBusinessHour && isBusinessDay && !isHoliday;
      if (isStoreOpen) { showOpenBanner(); }

Don't:

  • Write a comment above a complex if statement to explain what it does.
    • Bad: // Show banner if the store is currently open above if (currentHour >= OPENING_HOUR...)

2. Function Structure & Size

2.1 Keep Functions Small

Functions should be small. Keep blocks inside control structures short, often a single call.

Do:

  • Extract fiddly math and nested loops into named helper functions.
  • Favor a short block inside if, else or while statements, ideally a single function call.

Don't:

  • Write long functions that mix high-level conditions with low-level math and nested loops.

2.2 Do One Thing

A function should do exactly one thing. The litmus test: you cannot extract another meaningful function from it.

Do:

  • Test your functions: if you can label sections with comments like // Validation, // Storage, // Notification, extract each into its own function.
  • Test your extractions: if extracting a function produces a name that merely restates its body (e.g., uploadBasedOnSize), the ORIGINAL function was already doing one thing. If the extracted name represents a genuinely separate concept (e.g., uploadFileInParts), the original function was doing too much.

Don't:

  • Write "micromanager" functions that handle validation, calculation, database storage, and email notifications all at once.

2.3 Maintain One Level of Abstraction

A function should only contain code at a single, consistent level of abstraction, delegating deeper details to the next level down.

Do:

  • Keep every line at one level of abstraction, delegating deeper detail one level down.
    • Good: validateStock(); calculateTotalBill(); executeStripeCharge(); notifyWarehouse();

Don't:

  • Mix pure intent (high-level logic) with raw syntax (low-level logic) in the same function.
    • Bad: validateStockAvailability(); const finalBill = subtotal - discount + tax; Stripe.charges.create({ amount: finalBill * 100, source: order.token }); fetch("https://warehouse...");

3. Arguments & Data Flow

3.1 Minimize Function Arguments

Fewer arguments read cleaner. If you reach three or more, wrap them in an object. Avoid boolean flags and output arguments.

Do:

  • Strive for zero arguments (fetchData()), one argument (fileExists(path)), or two if they are a natural pair (moveTo(x, y)).
  • Group related arguments into objects.
    • Good: saveUser(user) (where user is an object containing name, email, age, etc.)

Don't:

  • Pass long argument lists (saveUser(name, email, age, city, isPremium)), output arguments that mutate inputs instead of returning (findMax(numbers, result)), or boolean flags (createUser(true)) that force two code paths from one function (violates "Do One Thing").
  • Pass two unrelated arguments as peers (sendEmail(message, smtp)); make one the owner: smtp.sendEmail(message).

3.2 Command Query Separation (& No Hidden Side Effects)

A function should either perform an action (Command) or answer a question (Query), but never both. It should never harbor hidden side effects.

Caveat: narrow, well-named mutate-and-report idioms (pop(), tryAdd(), tryAcquireLock()) are fine when the name itself signals the combined action. The rule targets functions whose name promises only a query but secretly acts too, not idioms that advertise the action up front.

Do:

  • Ensure functions only do what their names say. Let side effects happen elsewhere.
    • Good: if (checkPassword(password)) { initializeSession(); }

Don't:

  • Hide side effects inside seemingly harmless functions.
    • Bad: A checkPassword() function that invisibly calls Session.initialize() or resets user properties.

4. Architecture & Error Handling

4.1 Handle Switch Statements with Polymorphism

Switch statements inherently do multiple things. Bury them in abstract factories and use polymorphism instead.

Language caveat: this is object-oriented advice. With compiler-checked exhaustive matching, a match/switch over a closed set of variants is idiomatic and safe. In Rust the compiler enforces exhaustiveness and flags any unhandled case when a new variant is added; Go has no such compiler check (a switch missing cases builds clean and go vet passes), so exhaustiveness there needs the external nishanths/exhaustive linter. Reach for polymorphism when the type set is open; a compiler-checked match already handles a closed one.

Do:

  • Bury the switch in a factory (EmployeeFactory.create(type)) behind an interface (e.g., Employee).
  • Let each class handle its own logic via polymorphism.
    • Good: const employee = factory.create('fullTime', data); employee.calculatePay(); employee.getBenefits();

Don't:

  • Copy the same switch(employee.type) block into function after function (calculatePay, getBenefits, getSchedule).

4.2 Separate Error Handling from Business Logic

Throw exceptions instead of returning error codes. Keep the algorithm and its error handling in separate functions. Where failure modes are known, write the try-catch-finally skeleton (and the exceptions it throws) first, then fill in the logic.

A message that masks one field and interpolates an exception object beside it re-leaks what it just hid. A caught error's own rendering carries the thing the redaction removed: str(OSError) carries the absolute path, and the same shape recurs wherever a wrapper's Display quotes its source. Interpolate the narrow field (strerror, errno, reason, a status code), never the exception.

Do:

  • Use try/catch for a clean list of steps.
    • Good: try { createAccount(); createProfile(); } catch (error) { showError(); }
  • Extract the algorithm into its own function that throws; keep a separate function whose only job is to catch.
    • Good:
      function sendMessage(msg) {
        try {
          deliverMessage(msg);            // catch knows nothing about the algorithm
        } catch (error) {
          notifySender(msg.token, error);
        }
      }
      
      function deliverMessage(msg) {       // algorithm knows nothing about error handling
        const channel = resolveChannel(msg.to);
        broadcast(channel, moderate(msg.text));
      }

Don't:

  • Return error codes that push the caller into nested if/else checks.
  • Share ErrorCode enums globally, tying the whole codebase together.

4.3 Don't Repeat Yourself (DRY)

Extract repeated logic (API fetch boilerplate, timeout: 5000, if (!res.ok) throw error) into a single authoritative function; duplicating it guarantees silent bugs when you update one copy and forget the others. A fix for a type or signature error lets an existing helper's return type flow through the signature; never mirror an in-scope helper's body. A helper extracted only to dedupe is justified by two or more true duplicates; exactly one caller means inline it; dedupe alone never excuses a pass-through (§4.6).

Don't:

  • Merge two blocks that only look alike today but encode different business rules with different reasons to change (coincidental duplication). Only extract duplication that shares one true reason to change; two validation functions with matching checks today can still diverge tomorrow if they answer different questions.

4.4 The Law of Demeter

A method should only call methods on its immediate dependencies ("friends"), never dig through them to touch the internals of "strangers."

Do:

  • Tell the immediate object what you need it to do directly.
    • Good: let bufferOutputStream = ctxt.createScratchFileStream(classFileName);

Don't:

  • Chain method calls to burrow into an object's internal structure.
    • Bad: ctxt.getOptions().getScratchDir().getAbsolutePath()

4.5 Objects vs. Data Structures

Keep objects (hide data, expose behavior) separate from data structures (expose data, no behavior); never blend the two into hybrids. Choose procedural code (data structures plus separate procedures) when you expect to add new operations; choose object-oriented code when you expect to add new types. Expose abstract behavior, not getters/setters that mirror the exact stored fields.

Do:

  • Use data structures with separate procedure classes when new functions arrive frequently.
    • Good:
      class Square { public double side; }                 // data structure
      class Geometry {
        double area(Object shape) { ... }                  // add perimeter(), diagonal()... freely
      }
  • Expose what the caller needs, not the fields you happen to store.
    • Good: getPercentFuelRemaining(), which hides whether the reading came from gallons, litres, or a sensor.
    • Bad: getFuelTankCapacityInGallons() plus getGallonsOfGasoline(), which makes every caller do the division and pins the API to the storage unit.

Don't:

  • Build "hybrid" classes that carry private data with getters/setters and also real business logic.
  • Reflexively treat everything as an object regardless of how the code evolves.

4.6 Deep Modules

A module is anything with an interface: a function, a class, a package. It earns its place by hiding a lot of behavior behind a small interface. The interface is everything a caller must know: the signature plus invariants, ordering constraints, error modes, required configuration and performance characteristics. Depth is measured at the interface, so a deep module can be built from the small functions of §2.

Do:

  • Apply the deletion test: imagine deleting the module. If complexity reappears across its callers, it earns its keep.
  • Let callers and tests cross the same interface.

Don't:

  • Keep a pass-through: if deleting the module makes complexity vanish, delete it, unless something varies across it or it is a migration shim.
  • Test past the interface; wanting to usually means the module has the wrong shape.

5. Comments

5.1 Comments Lie; Use Them Sparingly and Intentionally

Avoid comments that explain what code does, since they eventually rot into outdated lies. Comment only to explain why, or to leave a necessary warning; when you must, keep it specific, tied to a real constraint, and readable as plain text.

Do:

  • Write code so clear it doesn't need comments.
  • Explain business intent: // prevents abuse while keeping free tier viable
  • Write warnings: // WARNING: Takes too long to run. Skip during quick test cycles.
  • Clarify complex math/regex: // 3-20 alphanumeric chars
  • Mark known tech debt with a specific note naming what to fix and when: // TODO: add timeout check; response > 5s freezes the UI
  • Document public APIs with the language's doc-comment format (/// rustdoc, /** */ JSDoc): the public surface is the one place comments earn their keep, since it's the contract callers read.

Don't:

  • Write comments explaining basic code behavior.
  • Leave old comments behind when refactoring logic.
    • Bad: Leaving // User must be 18 or older above code that was updated to if (user.age >= 21).
  • Write "mumbling" comments that lack context.
    • Bad: // R.J. said this might cause a race condition... not sure if it works

5.1.1 A Count in a Comment Is a Claim With an Expiry

A comment carrying a count or a universal ("both call sites", "every output is 64x48", "nothing observes this") is measured against one state of one file, and the round that adds a pin is the round that makes the previous round's count false. Two rules keep it honest: name the file the count was measured in and how to re-derive it, or downgrade the sentence to the measurement behind it. And when a comment states what NO test covers, the quantifier belongs over the ASSERTIONS, never over the artifacts the suite produces: "no test reads a value above the cap" and "no output above the cap exists" are different claims with different truth values over the same suite, and the second is the one that ships false.

A short restatement beside a longer precise statement is where drift lands. Two artifacts say the same thing, only one of them ever gets re-derived, and the compression is what goes stale. Point at the precise statement rather than restating it shorter.

5.2 Rely on Version Control, Not Comments

Never use comments to store old code, authorship, or history logs; and don't use comments to compensate for poorly structured code.

Do:

  • Delete commented-out code entirely.
  • Rely on git log for old versions, authorship, change history.
  • Write clean, small functions that do one thing, so you don't need comments to track where blocks end.
    • Good:
      function generateReport(data) {
          const validItems = filterValid(data);
          const results = processItems(validItems);
          return buildReport(results);
      }

Don't:

  • Leave half-dead commented code in your files.
  • Keep authorship tags (e.g., // Created by John Doe - March 2019).
  • Keep journal logs, closing-brace labels, or section markers (// 11-Oct-2001: Renamed getUserInfo..., } // end outer for loop, // ======== HELPERS ========).

6. Code Organization & Formatting

6.1 The Newspaper Metaphor (Vertical Formatting)

Order a source file top-down: highest-level summary first, deeper implementation below.

Do:

  • Place your highest-level function at the top of the file.
  • Place every supporting function just below its caller.
  • Group utility functions that serve a similar purpose together at the bottom (Conceptual Affinity).

Don't:

  • Scramble functions in a random order.
  • Force developers to scroll up and down endlessly to find how a function is implemented.

6.2 Visual Hierarchy via Vertical Spacing

Use blank lines to separate distinct concepts. Keep related lines vertically dense so the hierarchy stays scannable.

Do:

  • Use a blank line to indicate a new concept is starting.
  • Keep related lines of code tightly grouped together (vertically dense).
  • Use proper indentation for each scope level.

Don't:

  • Write walls of text with no spacing, or blank lines between every single line (both hide the hierarchy).

6.3 Variable Proximity and Team Standards

Declare variables exactly where they're used to cut mental baggage. Follow your team's formatting standards without argument.

Do:

  • Declare variables in the narrowest block that uses them, right before they are needed.
  • Keep shared class properties in one designated place (usually the top of the class).
  • Follow the team's calls on tabs vs. spaces, quote style, brace placement.

Don't:

  • Declare all variables at the top of a function if they aren't used until the end.
    • Bad: let report; ... // 20 lines of irrelevant code ... report = buildReport();
  • Scatter shared class properties throughout a class just to be near one specific function.

Quick Reference Cheat Sheet

CategoryDoDon't
NamingNames that reveal intent, are pronounceable, and match scope lengthCryptic abbreviations, identical-looking chars, noise suffixes (Manager/Data), Hungarian encodings (strName)
Self-documenting codeExtract complex logic into well-named booleans, helper functions, named constants (ONE_DAY_IN_MS)Comments explaining messy code, single-letter variables (d), raw magic numbers (86400000)
FunctionsSmall functions, one thing each, single level of abstractionMassive functions mixing high-level decisions with low-level API calls
ArgumentsZero or one arg; group 3+ into an objectLong arg lists, boolean flags, output arguments, hidden side effects
Control flowCommands (do things) or Queries (answer things), never both; named mutate-and-report idioms (pop(), tryAdd()) are the exceptionFunctions that mutate state and return values under a name that promises only a query
ErrorsThrow exceptions; write the try-catch-finally skeleton first; keep error handling in its own function, separate from the algorithmReturn error codes forcing nested if/else; global error enums; bolt try/catch on as an afterthought
DuplicationExtract shared logic into a single authoritative place (DRY), only when it shares one true reason to changeCopy-pasting switch statements or API boilerplate into file after file; merging coincidentally-identical blocks that encode different business rules
TypesPolymorphism via interfaces/factories for type-dependent behaviorRepeated switch(type) blocks duplicated in every function
CouplingAsk immediate dependencies to act directly (Law of Demeter)Chain calls (a.getB().getC().getD()) to reach into internal structure
Objects vs. dataPure data structures (DTOs) hold data; behavior lives in separate objectsHybrid classes carrying both getters/setters and business logic
Procedural vs OOProcedural when adding operations, OO when adding types (anti-symmetry)Forcing everything into objects regardless of how the code evolves
Data abstractionExpose abstract behavior that hides how data is storedGetters/setters that mirror the exact stored fields
ModulesDeep: a small interface over much behaviorPass-through wrappers that fail the deletion test (seams and migration shims aside)
CommentsExplain why, warnings, specific plain-text TODOs, public API docsExplain what code does, mumbling comments, HTML-formatted comments
Version controlRely on git log for history and authorship; delete dead codeCommented-out code, authorship tags, journal logs, closing brace comments
File structureHeadline function at top, callers above callees, related utilities groupedRandom function order, scrolling endlessly to find implementations
Vertical spacingBlank lines between concepts, tight grouping for related linesWalls of text with no spacing, or blank lines between every single line
Variable proximityDeclare variables right where they are used; follow team formatting standardsVariables declared 20 lines before use; personal style over team conventions

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.