agentleFS
healthier-vitaminshealthier-vitamins/agentic-grimoire/skills/keystone/SKILL.md

keystone

Skill2 starsChanged 10 days agoMITView on GitHub

Write code for the next junior reader instead of for the compiler. Use when implementing non-trivial logic, structuring a module, or judging whether existing code can be read.

1 other project uses a version of this.

Adopted by

Most recently taken up by

  • Other versions1 project uses a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 1

    1. stamat/claude★ 0same 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 repository16 other files it gives its agents.

The file

Show its rules and text

We split this skill into the rules it gives an agent

13 rules. About 0 are common, 12 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈12

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Every rule below serves one of the three.

    line 13
  2. Distinctive:

    Every feature owns one file that holds its flow — the keystone, the stone the arch depends on.

    line 45
  3. Distinctive:

    SLAP: every statement in a function body sits at the same level.

    line 75
  4. Very specific:

    No-op word test: Delete each word from the name.

    line 101
  5. Distinctive:

    When a file feels too large, the question is not its length.

    line 143
  6. Distinctive:

    Every one of these holds for the code just written:

    line 158
  7. Distinctive:

    Every file's public surface is marked, and its non-public functions are not.

    line 160
  8. Distinctive:

    Every file is in newspaper order — no callee defined above its caller.

    line 161
  9. Distinctive:

    Every name survives the no-op word test, and counterpart names share a frame.

    line 162
  10. Distinctive:

    Every function holds one level of abstraction.

    line 163
  11. Distinctive:

    Every new file's folder was stated as a claim, on the tree's existing axis.

    line 164
  12. Distinctive:

    Every pattern introducing runtime dispatch has ≥3 variants and a literal table.

    line 165
  13. Distinctive:

    Every module with a public surface has a direct test naming its behaviour.

    line 166

≈ “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

The reader is the constraint. Ask three questions of every design (Ousterhout, A Philosophy of Software Design):

  • Change amplification — how many places must change to make one change?
  • Cognitive load — how much must the reader hold in their head to be correct here?
  • Unknown unknowns — can the reader tell which code a change might break?

Every rule below serves one of the three. When two rules collide, the one lowering cognitive load wins.

1. Coupling decides distance

Connascence (Page-Jones) ranks how strongly two pieces of code know about each other, weakest to strongest:

name < type < meaning < position < algorithm

The rule: the stronger the connascence, the closer together the code lives. Two functions that agree on a name can sit in different packages. Two that agree on the meaning of a magic value, or on argument order, or on a shared algorithm, belong in the same file — because a reader changing one must find the other, and only proximity makes that possible.

Cross-file connascence of meaning or position is what makes tracing exhausting: the knowledge needed to be correct lives somewhere the reader cannot see. Full ranking, including the dynamic forms (execution, timing, value, identity), in references/philosophy.md.

2. Behaviour is obvious from the unit alone

Locality of behaviour (Gross): reading one function tells the reader what it does, without opening another file.

This trades against DRY, and the trade has a direction: duplicate a small expression before you extract a shared helper that both callers must open to understand. Extract when the shared thing has a name worth learning, not when two lines happen to match.

3. The keystone file

Every feature owns one file that holds its flow — the keystone, the stone the arch depends on. It reads top-to-bottom, naming every step in order (Template Method or Pipeline). Tracing the feature means reading that one file.

Newspaper order (Clean Code ch. 5): the public entry sits at the top, its callees below it, depth increasing downward. A reader landing at line 1 is standing at the door, and reading downward is descending the call graph.

Where a module-level value must be defined after the functions it references, wrap it in a function so the ordering survives: def _route_chain(): return [...] at the top reads as the file's table of contents.

Split code out when the piece earns a name the keystone calls. Helpers are deep modules (Ousterhout): small interface, deep implementation. A file that only forwards to another folds back into its caller.

4. The public surface is visible on landing

A reader who opens a file must see, without scanning it, which functions are the door and which are furniture. Mark it with the language's own mechanism — a leading underscore in Python plus __all__ at the top; the export keyword in TypeScript. Everything one file uses stays unmarked.

A module's public surface has direct tests. A public function reachable only through end-to-end tests is unreadable by construction: there is no way to learn what it does except by tracing it, which is the cost this whole skill exists to remove. (tdd owns how to write them.)

5. One level of abstraction per function

SLAP: every statement in a function body sits at the same level. A function that orchestrates four pipeline stages does not also strip a suffix off a string — the reader cannot tell which lines matter.

This is what "no god functions" means operationally, and it is about nesting and mixed altitude rather than length (Campbell's cognitive complexity, see references/philosophy.md). A 200-line function that is twelve named calls in sequence reads fine. A 40-line function three levels deep does not.

6. Every meaningful step carries a name

A named function or named variable per step; the arithmetic hides inside the name.

subtotal = add(base_price, tax)
total    = add(subtotal, shipping_fee)

7. Names spell out what they hold

  • Full words, naming the noun held or the verb performed. Name length scales with scope: a loop index stays short, a module-level export spells everything out.
  • Frames and minimal pairs. Counterpart names along one dimension share the whole frame and differ only in the varying token: sql_and_matches / sql_or_matches. Name the frame first (sql_<op>_matches), then instantiate its members, so renaming one renames all its siblings. (Ousterhout ch. 14, consistent naming.)
  • No-op word test. Delete each word from the name; if the meaning inside the current scope survives, the word stays deleted. sql_and_filter_matches → sql_and_matches: "filter" is a no-op because every match came from a filter.

Vocabulary note: frame is the naming dimension (§7); axis is the placement dimension (§8). They are different ideas — keep the words apart.

8. Placement is a claim

Creating a file asserts "this belongs here". State in one line which folder it goes in and why.

  • Each tree level sorts by one axis. Pick the app's dominant axis and hold it: pipeline app → stages (preprocessing/), product app → features (screaming architecture, Martin), library → capabilities. An existing axis in the repo wins.
  • A folder mixing two axes at one depth (a services/ beside a preprocessing/) is the smell that placement stopped being a claim.
  • A framework's prescribed layout (NestJS modules, Rails MVC, Next.js app router) is the axis — scaffold with it.
  • Layered frameworks resolve to vertical slices: top level is features, layers live inside each slice. Controller/service is a floor: when logic outgrows the service, grow the slice with new named files.
  • Orchestration has a canonical home — the use-case file inside its slice (Clean Architecture's interactors): partner_merge/merge_partners.usecase.ts.
  • utilities/ earns its name only when every file in it is domain-free and consumed by ≥2 slices. One consumer means the code lives in that slice. (Google's Go style guide bans grab-bag util/common packages for the same reason.)

9. Pattern before bespoke structure, and the pattern pays rent

Map the problem to an established pattern and state the pattern plus a one-line reason before writing code. Catalog in references/philosophy.md. Where no pattern fits, say so and use the simplest direct structure.

Patterns buy structure with indirection, and the reader pays. A pattern that replaces readable dispatch with runtime dispatch — Chain of Responsibility, Strategy, a handler map — earns it when there are three or more variants, and it stays readable when the dispatch table is a literal list in the same file, in execution order, with the selecting condition inline. Two variants read better as an if.

10. The seam test — is this one feature or two?

When a file feels too large, the question is not its length. It is: to change A, must I read B? If a change to one half never requires reading the other, they are two features wearing one name, and the fix is a second named file rather than extracted helpers. Git history settles it — commits touching A that never touch B were never one feature. (Parnas, On the Criteria To Be Used in Decomposing Systems into Modules.)

The cheap confirmation: the name needs an "and". route_and_merge is decide_merge_route plus apply_merge_route.

Length itself is not a rule here. No line-count ceiling replaces the seam test, because a 600-line file a reader can enter and leave costs less than a 150-line file that hides its door.

Done when

Every one of these holds for the code just written:

  • Every file's public surface is marked, and its non-public functions are not.
  • Every file is in newspaper order — no callee defined above its caller.
  • Every name survives the no-op word test, and counterpart names share a frame.
  • Every function holds one level of abstraction.
  • Every new file's folder was stated as a claim, on the tree's existing axis.
  • Every pattern introducing runtime dispatch has ≥3 variants and a literal table.
  • Every module with a public surface has a direct test naming its behaviour.
  • The seam test was applied to any file that felt too large.

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.