agentleFS
denysdovhandenysdovhan/agents/skills/readable-code/SKILL.md

readable-code

Skill21 starsChanged 10 days agoMITView on GitHub

Readable code rules inspired by The Art of Readable Code, for any language with TypeScript/JavaScript as the primary focus. Use when writing, reviewing, or refactoring code in TS, JS, React/JSX, Node, Python, or any other language, including when the user asks to clean up, simplify, untangle, or make code easier to follow. Enforces short functions, flat control flow, clear naming, readable structure, and language idioms.

2 other projects use a version of this.

Adopted by

Most recently taken up by

  • Other versions2 projects use a version of this.

    Word for word · 1

    1. denysdovhan/skills★ 21100% same

    Edited · 0

    None found.

    Wrote their own version · 1

    1. Mehul72/skills★ 1same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository4 other files it gives its agents.

The file

Show its rules and text

We split this skill into the rules it gives an agent

24 rules. About 0 are common, 17 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈17

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    When editing existing code, apply the rules to the code you touch.

    line 24
  2. Distinctive:

    When reviewing, cite the rule number with each finding so the author can look up the reasoning.

    line 26
  3. Very specific:

    Never nest more than 2 levels deep: If you have a loop inside a loop, or an if inside a loop inside an if, extract the inner block into a …

    line 40
  4. Distinctive:

    Use early returns / guard clauses to handle edge cases at the top, keeping the main logic flat.

    line 43
  5. Very specific:

    Prefer continue or break to skip iterations rather than wrapping the body in a conditional.

    line 45
  6. Very specific:

    Pack information into names: Use specific, concrete words — fetchPage not get, retryCount not n.

    line 71
  7. Very specific:

    Use names that can't be misconstrued: If a range is inclusive, say maxItems not limit.

    line 75
  8. Very specific:

    Follow the language's casing convention (camelCase in TS/JS, snake_case in Python) and the codebase's naming patterns.

    line 82
  9. Very specific:

    Put the changing/interesting value on the left side of comparisons: if (length > 10) not if (10 < length).

    line 87
  10. Very specific:

    Avoid the ternary operator for anything non-trivial — if it's not immediately obvious, use an if/else.

    line 93
  11. Distinctive:

    Use explaining variables to break complex expressions into named pieces.

    line 98
  12. Distinctive:

    Use summary variables to capture a long expression that's used more than once.

    line 99
  13. Distinctive:

    If a block of code is solving a subproblem unrelated to the main goal of the function, extract it.

    line 118
  14. Distinctive:

    Declare variables close to where they're used: Don't declare at the top of a function if it's only used 30 lines later.

    line 134
  15. Distinctive:

    Eliminate unnecessary variables: If a variable is used only once and doesn't clarify anything, inline it.

    line 140
  16. Distinctive:

    If a value has meaning, give it a name.

    line 147
  17. Distinctive:

    If a function needs many config-like options, pass a single options object.

    line 154
  18. Distinctive:

    If the codebase does something one way, do it the same way.

    line 161
  19. Distinctive:

    When joining an existing codebase, match the existing conventions even if you'd prefer a different style.

    line 164
  20. Distinctive:

    Remove dead code. Commented-out code is dead code.

    line 174
  21. Distinctive:

    Use the standard library and platform APIs before writing custom solutions.

    line 175
  22. Distinctive:

    Don't comment what the code does — the code already says that.

    line 179
  23. Distinctive:

    Don't comment bad code — rewrite it: If you need a comment to explain what a block does, extract it into a well-named function instead.

    line 185
  24. Distinctive:

    Write code that looks good after the project's formatter runs, if it has one (Prettier, Biome, Black, Ruff).

    line 190

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “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

Readable Code Rules (/readable-code)

Apply these rules when writing, reviewing, or refactoring code. Inspired by The Art of Readable Code by Dustin Boswell and Trevor Foucher.

Core principle: Code should be easy to understand. The time it takes someone else (or future you) to understand the code is the ultimate metric.

How to Apply

  • The general rules below apply to every language. Examples use TypeScript.
  • Load the language reference for idioms:
    • TypeScript / JavaScript / JSX: references/typescript.md
    • Python: references/python.md
    • Other languages: apply the general rules plus that language's own idioms.
  • The project's linter, formatter, and existing conventions win over these rules. Readability is partly familiarity, so a consistent codebase beats a locally "better" style.
  • When editing existing code, apply the rules to the code you touch. Mention other problems instead of rewriting unrelated code.
  • When reviewing, cite the rule number with each finding so the author can look up the reasoning.

1. Keep Functions Short and Focused

  • A function should do one thing. If you can describe what it does with "and", split it.
  • Aim for functions that fit on one screen (~15-25 lines). If it's longer, extract sub-tasks.
  • Each function should operate at a single level of abstraction — don't mix high-level logic with low-level details in the same function.

2. Flatten Control Flow — No Deep Nesting

  • Never nest more than 2 levels deep. If you have a loop inside a loop, or an if inside a loop inside an if, extract the inner block into a helper function with a descriptive name.
  • Use early returns / guard clauses to handle edge cases at the top, keeping the main logic flat.
  • Prefer continue or break to skip iterations rather than wrapping the body in a conditional.
  • Replace complex conditionals with well-named helper functions or variables that explain the intent.
// Bad: nested and hard to follow
for (const user of users) {
  if (user.isActive) {
    for (const order of user.orders) {
      if (order.isPending) {
        process(order);
      }
    }
  }
}

// Good: flat, each function name explains what it does
const activeUsers = getActiveUsers(users);
for (const user of activeUsers) {
  processPendingOrders(user.orders);
}

3. Name Things Clearly

  • Pack information into names. Use specific, concrete words — fetchPage not get, retryCount not n.
  • Avoid generic names like tmp, data, result, val, info, handle — unless the scope is tiny (2-3 lines).
  • Use names that can't be misconstrued. If a range is inclusive, say maxItems not limit. If a boolean, use is, has, should, can prefixes.
  • Match the name length to the scope. Short names for small scopes, descriptive names for wide scopes.
  • Don't use abbreviations unless they're universally understood (num, max, min, err, id, url are fine; svcMgrCfg is not).
  • Follow the language's casing convention (camelCase in TS/JS, snake_case in Python) and the codebase's naming patterns.

4. Make Control Flow Easy to Follow

  • Put the changing/interesting value on the left side of comparisons: if (length > 10) not if (10 < length).
  • Order if/else blocks: positive case first, simpler case first, or the more interesting case first.
  • Minimize the number of variables the reader has to track. Reduce the mental footprint of each block.
  • Avoid the ternary operator for anything non-trivial — if it's not immediately obvious, use an if/else. Never nest ternaries.

5. Break Down Giant Expressions

  • Use explaining variables to break complex expressions into named pieces.
  • Use summary variables to capture a long expression that's used more than once.
  • Apply De Morgan's laws to simplify negated boolean expressions.
// Bad
if (!(age >= 18 && hasId && !isBanned)) {
  deny();
}

// Good
const isEligible = age >= 18 && hasId && !isBanned;
if (!isEligible) {
  deny();
}

6. Extract Unrelated Subproblems

  • If a block of code is solving a subproblem unrelated to the main goal of the function, extract it.
  • The helper function should be pure and self-contained — it shouldn't need to know about the calling context.
  • This is the single most effective way to improve readability: separate what you're doing from how.

7. One Task at a Time

  • Each section of code should do one task. If a function is doing parsing AND validation AND transformation, split them into separate steps.
  • List the tasks a function does. If there's more than one, reorganize so each task is in its own block or function.

8. Reduce Variable Scope

  • Declare variables close to where they're used. Don't declare at the top of a function if it's only used 30 lines later.
  • Minimize the "live time" of a variable — the fewer lines between its assignment and last use, the easier it is to follow.
  • Prefer write-once variables. Variables that are assigned once and never modified are easier to reason about.
  • Eliminate unnecessary variables. If a variable is used only once and doesn't clarify anything, inline it.

9. No Magic Numbers or Strings

  • Replace magic numbers and strings with named constants: if (retries > MAX_RETRIES) not if (retries > 3).
  • If a value has meaning, give it a name. The name documents the intent.
  • Group related constants together.

10. Fewer Function Arguments

  • Aim for 3 or fewer arguments per function. More than that is a smell.
  • Group related arguments into an object or named type.
  • If a function needs many config-like options, pass a single options object.
  • Boolean flag arguments are a sign the function does two things — split it instead. A call like render(user, true, false) can't be read without opening the definition.

11. Consistency

  • If the codebase does something one way, do it the same way. Don't mix styles.
  • Consistent naming patterns, consistent structure, consistent error handling.
  • When joining an existing codebase, match the existing conventions even if you'd prefer a different style.
  • Surprise is the enemy of readability — predictable code is readable code.

12. Write Less Code

  • The best code is no code at all. Question whether a feature is truly needed before implementing.
  • Don't over-engineer. Solve the problem at hand, not hypothetical future problems.
  • Remove dead code. Commented-out code is dead code.
  • Use the standard library and platform APIs before writing custom solutions.

13. Comments: Explain Why, Not What

  • Don't comment what the code does — the code already says that. Comment why it does it.
  • Comment flaws and workarounds: // TODO:, // HACK:, // XXX: with explanation.
  • Comment surprising behavior or non-obvious decisions — things where a reader would ask "why?".
  • Don't comment bad code — rewrite it. If you need a comment to explain what a block does, extract it into a well-named function instead.

14. Design Code to Survive Auto-Formatting

  • Write code that looks good after the project's formatter runs, if it has one (Prettier, Biome, Black, Ruff). If a chained expression or repeated pattern would be broken across 4+ lines by the formatter, extract a helper function instead.
  • Prefer one-line helper calls over long inline chains that the formatter will expand vertically.
  • The formatter is your reader's first impression. Run it before committing — if the result looks ugly, that's a signal to refactor, not to disable the formatter.
// Bad: Prettier wraps this into a tall chain in the middle of the handler
const users = await db
  .selectFrom("users")
  .where("active", "=", true)
  .leftJoin("orders", "orders.userId", "users.id")
  .orderBy("users.createdAt", "desc")
  .limit(pageSize)
  .execute();

// Good: extract a helper so the call site stays clean
function getActiveUsers(db: Database, pageSize: number) {
  return db
    .selectFrom("users")
    .where("active", "=", true)
    .leftJoin("orders", "orders.userId", "users.id")
    .orderBy("users.createdAt", "desc")
    .limit(pageSize)
    .execute();
}

const users = await getActiveUsers(db, 20);
// Bad: inline lookup chain — Prettier expands it to 5+ lines
const config = Object.fromEntries(
  requiredKeys.map((key) => [key, settings[key] ?? defaults[key] ?? fallbacks[key]]),
);

// Good: extract the lookup
const resolveSetting = (key: string) => settings[key] ?? defaults[key] ?? fallbacks[key];

const entries = requiredKeys.map((key) => [key, resolveSetting(key)]);
const config = Object.fromEntries(entries);

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.