Habit · loads whenever its situation comes up, at any step

ponytail

about 2,500 tokens

ponytail as it installs, each line coloured by where its words came from.

  • 3 files
  • 2 edits
  • 123 sentences left out
  • 3 sources
  • last changed 2026-10-17

The text

SKILL.md

about 1,500 tokens
  • Dietrich Gebert's Ponytail
  • pstack
  • greenline

---

name: "ponytail"

description: "Minimalism at any step: before writing code the request leaves open, climb the lazy-senior ladder (does it need to exist, is it already in the repo, does the stdlib or platform cover it, can it be one line) and build only on a measured need; subtract before you add; keep call chains flat; migrate every caller and delete the old API in one wave; mark each deliberate shortcut with a ponytail: comment naming its ceiling. Use before writing code the request leaves open, when refactoring or simplifying, when a new internal API replaces an old one, and when asked what was deferred."

---

Dietrich Gebert's Ponytailponytail/SKILL.md

# Ponytail, lazy senior dev mode

greenlineOpens the habit: code the request leaves open, bounded by acceptance

ponytail is the habit for the moment code the request leaves open is about to be written, a refactor or a simplification of code that works begun, a new internal API introduced while old callers remain, or the owner asks what was deferred, at whatever step the work is in, most often build; code the request plainly asks for does not load it. It writes no record of its own: a shortcut it takes is marked in the code and named in the build section of the change record. Where the ladder says reuse or skip, the change's acceptance still decides the scope, and tdd still decides the tests: a smaller implementation satisfies them too. The review step's excess lens reads a committed range for what can go; this habit runs before the code exists.

Dietrich Gebert's Ponytailponytail/SKILL.md

You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written.

Before writing any code, stop at the first rung that holds:

1. Does this need to be built at all? (YAGNI)

2. Does it already exist in this codebase? Reuse the helper, util, or pattern that's already here, don't re-write it.

3. Does the standard library already do this? Use it.

4. Does a native platform feature cover it? Use it.

5. Does an already-installed dependency solve it? Use it.

6. Can this be one line? Make it one line.

7. Only then: write the minimum code that works.

greenlineBuilds only on a measured need; a delegated choice takes that answer

Build only on a need you measured. Where the first rung turns on a measurement, take it before building; where it shows no need, say so with the numbers and build nothing. A choice the owner leaves to you takes that answer; the owner, told the numbers, may still ask for the build.

Dietrich Gebert's Ponytailponytail/SKILL.md

The ladder runs after you understand the problem, not instead of it: read the task and the code it touches, trace the real flow end to end, then climb.

Bug fix = root cause, not symptom: a report names a symptom. Grep every caller of the function you touch and fix the shared function once — one guard there is a smaller diff than one per caller, and patching only the path the ticket names leaves a sibling caller still broken.

Rules:

- No abstractions that weren't explicitly requested.

- No new dependency if it can be avoided.

- No boilerplate nobody asked for.

- Deletion over addition. Boring over clever. Fewest files possible.

- Shortest working diff wins, but only once you understand the problem. The smallest change in the wrong place isn't lazy, it's a second bug.

- Question complex requests: "Do you actually need X, or does Y cover it?"

- Pick the edge-case-correct option when two stdlib approaches are the same size, lazy means less code, not the flimsier algorithm.

- Mark deliberate simplifications that cut a real corner with a known ceiling (global lock, O(n²) scan, naive heuristic) with a `ponytail:` comment naming the ceiling and upgrade path, and name it in the build section of the change record.

Not lazy about: understanding the problem (read it fully and trace the real flow before picking a rung, a small diff you don't understand is just laziness dressed up as efficiency), input validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs (the platform is never the spec ideal, a clock drifts, a sensor reads off), anything explicitly requested. Lazy code without its check is unfinished: non-trivial logic leaves ONE runnable check behind, the smallest thing that fails if the logic breaks (an assert-based demo/self-check or one small test file; no frameworks, no fixtures). Trivial one-liners need no test.

pstackprinciple-subtract-before-you-add/SKILL.md

When evolving a system, remove complexity first, then build.

pstackprinciple-subtract-before-you-add/SKILL.md

Default to subtraction.

Make simplification a continual investment. Leave the design slightly simpler and more capable behind the same or smaller surface than you found it.

**The pattern:**

- Sequence removal before construction

- Cut before you polish (get to the minimum before investing in quality)

- Design for observed usage, not speculative edge cases

- No speculative validators, parsers, or guards beyond what the spec demands

pstackprinciple-laziness-protocol/SKILL.md

- **Maintain a flat call hierarchy.** Avoid deep call chains. A rich interface that hides substantial work is not a deep call chain. If answering a question requires tracing through more than 3 files or layers, flatten it.

- **Consolidate decisions.** Do not repeat the same choice in several places. Put it behind one source of truth and pass the result as a simple flag.

pstackprinciple-laziness-protocol/SKILL.md

- **Question the threading.** If a task asks you to pass a new signal through types, schemas, pipelines, or similar layers, stop and look for a more direct path.

- **Sweat the small leaks.** Remove tiny pass-throughs, representation leaks, and duplicated choices before they spread. Small leaks compound into permanent coordination costs.

**The test:** If a human developer would find the code exhausting to maintain, it is a bad solution.

greenlineMigrate-callers-then-delete becomes a section of the habit

## Migrate the callers, then delete the old API

pstackprinciple-migrate-callers-then-delete-legacy-apis/SKILL.md

When we decide a new API is the right design, migrate callers and remove the old API in the same refactor wave instead of preserving compatibility layers.

**Rule:**

- Do not keep legacy API paths only because internal callers still exist

- Inventory callers, migrate them, and delete the old API immediately

- Treat temporary adapters as exceptional and time-boxed, not default architecture

pstackprinciple-migrate-callers-then-delete-legacy-apis/SKILL.md

**When this applies:**

- No external users depend on backward compatibility

- The project can absorb coordinated breaking changes

- The new API is part of a simplification or refactor initiative

Keeping both old and new APIs creates dual-path complexity, slows cleanup, and makes the codebase feel append-only.

greenlineA refactor, replacing working code included, reads simplify.md first

## Refactoring and deferrals

Replacing code that already works is a refactor, a scan by an index or a loop by a library call included: before its first edit, read [simplify.md](simplify.md) whole: why the code is there, behavior kept exactly, the repository's conventions, the scope of what changed, and one change at a time. When the owner asks what was deferred, harvest the `ponytail:` markers by [debt.md](debt.md).

SKILL.md as installed, byte for byte SHA-256 cf4dac874fb1080d996d7a8fbdd8ce47acfbdfca8772e96bc667d0e7885e63e0

simplify.md

about 660 tokens
  • Addy Osmani's agent-skills
  • greenline

Addy Osmani's agent-skillscode-simplification/SKILL.md

Don't change what the code does — only how it expresses it. All inputs, outputs, side effects, error behavior, and edge cases must remain identical. If you're not sure a simplification preserves behavior, don't make it.

```

ASK BEFORE EVERY CHANGE:

→ Does this produce the same output for every input?

→ Does this maintain the same error behavior?

→ Does this preserve the same side effects and ordering?

→ Do all existing tests still pass without modification?

```

Addy Osmani's agent-skillscode-simplification/SKILL.md

Simplification means making code more consistent with the codebase, not imposing external preferences. Before simplifying:

```

2. Study how neighboring code handles similar patterns

3. Match the project's style for:

- Import ordering and module system

- Function declaration style

- Naming conventions

- Error handling patterns

- Type annotation depth

```

Simplification that breaks project consistency is not simplification — it's churn.

Addy Osmani's agent-skillscode-simplification/SKILL.md

Default to simplifying recently modified code. Avoid drive-by refactors of unrelated code unless explicitly asked to broaden scope. Unscoped simplification creates noise in diffs and risks unintended regressions.

Addy Osmani's agent-skillscode-simplification/SKILL.md

Before changing or removing anything, understand why it exists. This is Chesterton's Fence: if you see a fence across a road and don't understand why it's there, don't tear it down. First understand the reason, then decide if the reason still applies.

```

BEFORE SIMPLIFYING, ANSWER:

- What is this code's responsibility?

- What calls it? What does it call?

- What are the edge cases and error paths?

- Are there tests that define the expected behavior?

- Why might it have been written this way? (Performance? Platform constraint? Historical reason?)

- Check git blame: what was the original context for this code?

```

If you can't answer these, you're not ready to simplify. Read more context first.

Addy Osmani's agent-skillscode-simplification/SKILL.mdgreenlineA refactor and a feature are two commits; PRs are outward acts

Make one simplification at a time. Run tests after each change. **Submit refactoring changes separately from feature or bug fix changes.** A commit that refactors and adds a feature is two commits: split them.

Addy Osmani's agent-skillscode-simplification/SKILL.md

```

FOR EACH SIMPLIFICATION:

1. Make the change

2. Run the test suite

3. If tests pass → commit (or continue to next simplification)

4. If tests fail → revert and reconsider

```

Avoid batching multiple simplifications into a single untested change. If something breaks, you need to know which simplification caused it.

debt.md

about 350 tokens
  • Dietrich Gebert's Ponytail
  • greenline

Dietrich Gebert's Ponytailponytail-debt/SKILL.md

Every deliberate ponytail shortcut is marked with a `ponytail:` comment naming its ceiling and upgrade path. This collects them into one ledger so a deferral can't quietly become permanent.

## Scan

Grep the repo for comment markers, skipping `node_modules`, `.git`, and build output:

`grep -rnE --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=build '(#|//|/[*]) ?ponytail:' .` (add other comment prefixes if your stack uses them)

Each hit is one ledger row. The comment prefix keeps prose that merely mentions the convention out of the ledger.

## Output

One row per marker, grouped by file:

`<file>:<line>, <what was simplified>. ceiling: <the limit named>. upgrade: <the trigger to revisit>.`

The convention is `ponytail: <ceiling>, <upgrade path>`, so pull the ceiling and the trigger straight from the comment. Want an owner per row too? add `git blame -L<line>,<line>`.

Flag the rot risk: any `ponytail:` comment that names no upgrade path or trigger gets a `no-trigger` tag, those are the ones that silently rot.

End with `<N> markers, <M> with no trigger.` Nothing found: `No ponytail: debt. Clean ledger.`

## Boundaries

greenlineThe harvest goes in the reply or the record, not a fileDietrich Gebert's Ponytailponytail-debt/SKILL.md

Reads and reports only, changes nothing. The harvest goes in the reply; where a change asked for it, the step's section of its change record carries it, and no file is written for it beside the code. One-shot.

The edits

Red is upstream's text; green is what greenline shipped in its place.

What the edit kinds mean
method
changes what the method does, under a recorded ruling
correction
fixes an error
scope
fits the text to this skill
pointer
re-points a reference
smaller edits
rename, relocate or adjust tool details
2 smaller edits

Renames, locations and tool details, each with its reason.

  1. Edit 1 relocate SKILL.md:37

    Upstream: Mark deliberate simplifications that cut a real corner with a known ceiling (global lock, O(n²) scan, naive heuristic) with a `ponytail:` comment naming the ceiling and upgrade path.

    Shipped: Mark deliberate simplifications that cut a real corner with a known ceiling (global lock, O(n²) scan, naive heuristic) with a `ponytail:` comment naming the ceiling and upgrade path, and name it in the build section of the change record.

    A deliberate shortcut is named in the build section, so it survives

    Full reason

    A deliberate shortcut's deferral is named in the change record's build section, which records each deviation and what was left alone, so it survives the session.

  2. Edit 2 tool details simplify.md:20

    Upstream: 1. Read CLAUDE.md / project conventions

    Shipped: 1. Read the agent instructions file, AGENTS.md or CLAUDE.md, and the repository's conventions

    Reads the agent instructions file, AGENTS.md or CLAUDE.md, not only CLAUDE.md

    Full reason

    Read CLAUDE.md names one harness's instructions file; the agent instructions file, AGENTS.md or CLAUDE.md, and the repository's conventions hold in any harness (R21).

What greenline wrote

The full reason for every passage greenline wrote, in the order of the text.

  1. SKILL.md:8 method

    One opening paragraph in the habit's own voice: the situations the block's rows key it by, code the request leaves open and not code it plainly asks for, since QA runs loaded it ahead of its situation (J-60, the fourth family); that it writes no record of its own and the build section names a shortcut, that acceptance and tdd still bound a smaller implementation, and where the review step's excess lens stands beside it. R1

  2. SKILL.md:22 method

    The first rung builds only on a measured need, and a choice the owner leaves to the agent takes a measurement's answer of none, since a QA run built an index after measuring no need (J-60, the fifth family). R1

  3. SKILL.md:41 scope

    principle-subtract-before-you-add's title becomes a section of the habit.

  4. SKILL.md:55 scope

    principle-laziness-protocol's title becomes a section of the habit, named for what its taken bullets keep flat: the call chain, the decisions and the threading.

  5. SKILL.md:64 scope

    principle-migrate-callers-then-delete-legacy-apis' title becomes a section of the habit.

  6. SKILL.md:80 method

    code-simplification's selected passages and ponytail-debt's harvest live on simplify.md and debt.md, read only on their branch, so the body names each page and what it holds; replacing working code is a refactor that reads simplify.md whole first, since a QA run replaced a working scan with an index and left it unread (J-60, the fifth family). R1

  7. simplify.md:1 scope

    code-simplification's selected passages make one page, read before a refactor or a simplification of code that already works; its title named the upstream skill.

  8. simplify.md:3 scope

    The first principle's heading, its number dropped with the principles not taken.

  9. simplify.md:15 scope

    The second principle's heading, its number dropped with the principles not taken.

  10. simplify.md:32 scope

    The fifth principle's heading, its number dropped with the principles not taken.

  11. simplify.md:36 scope

    The process's first step takes a heading of its own, Chesterton's fence named in its text.

  12. simplify.md:52 scope

    The process's third step takes a heading of its own.

  13. simplify.md:54 scope

    A PR is a forge's and an outward act the line does not run; the split the line runs is one commit per logical change, the build step's first rule.

    Credits: Addy Osmani's agent-skills

  14. debt.md:1 scope

    ponytail-debt opens with no title of its own; the page takes one naming what it does.

  15. debt.md:34 relocate

    ponytail-debt's ledger file becomes the reply, or the step's section of the change record when a change asked for the harvest, greenline's homes for what the agent reports.

    Credits: Dietrich Gebert's Ponytail

What it left out

Dietrich Gebert's Ponytail

Dietrich Gebert's Ponytail, ponytail/SKILL.md: all 36 sentences taken

Dietrich Gebert's Ponytail, ponytail-debt/SKILL.md: 2 of 20 sentences left out
  1. To persist it, ask and it writes the ledger to a file (e.g. `PONYTAIL-DEBT.md`). left out: The ledger file becomes the reply or the change record's section. replaced by line 34 of debt.md
  2. 1 sentence taken
  3. "stop ponytail-debt" or "normal mode" to revert. left out: The plugin's commands to leave its mode have no meaning here: the harvest is one reply.

pstack

pstack, principle-subtract-before-you-add/SKILL.md: 5 of 14 sentences left out
  1. # Subtract Before You Add left out: The title becomes a section of the habit. replaced by line 41 of SKILL.md
  2. 1 sentence taken
  3. **Why:** Adding to a complex system compounds complexity.
  4. Removing first leaves less code, reveals the essential structure, and usually makes the next design obvious. 2 sentences left out: The why restates the ladder's deletion over addition.
  5. 8 sentences taken
  6. Simplify prompts (remove redundant instructions, excessive templates)
  7. When a reference has no novel content, delete it rather than leaving a stub 2 sentences left out: Simplifying prompts and deleting a reference stub concern agent instructions, handed to the workshop craft craft-writing-for-agents.
pstack, principle-laziness-protocol/SKILL.md: 7 of 20 sentences left out
  1. # Laziness Protocol left out: The title becomes a section of the habit. replaced by line 55 of SKILL.md
  2. Aim for the most result with the least code and complexity. left out: The aim restates the ladder's opening.
  3. **Prefer deletion.**
  4. When asked to refactor or improve, look for removals before additions. 2 sentences left out: Prefer deletion restates the rule Deletion over addition. replaced by line 10 of SKILL.md
  5. 7 sentences taken
  6. **Minimize the diff.**
  7. Make the smallest change that solves the problem.
  8. Fewer lines beat "elegant" boilerplate. 3 sentences left out: Minimize the diff restates the rule Shortest working diff wins. replaced by line 10 of SKILL.md
pstack, principle-migrate-callers-then-delete-legacy-apis/SKILL.md: 2 of 12 sentences left out
  1. # Migrate Callers Then Delete Legacy APIs left out: The title becomes a section of the habit. replaced by line 64 of SKILL.md
  2. 5 sentences taken
  3. Update tests to assert the new contract, and delete tests that only protect pre-refactor implementation details left out: Deleting tests that protect pre-refactor details is not taken: a test is removed only through sweep-tests and its mutation proof (contradiction 23). R2

Addy Osmani's agent-skills

Addy Osmani's agent-skills, code-simplification/SKILL.md: 107 of 130 sentences left out
  1. # Code Simplification
  2. Inspired by the [Claude Code Simplifier plugin](https://github.com/anthropics/claude-plugins-official/blob/main/plugins/code-simplifier/agents/code-simplifier.md).
  3. Adapted here as a model-agnostic, process-driven skill for any AI coding agent. 3 sentences left out: The title and the credit to a Claude Code plugin give way to the page's own title (R21). replaced by line 1 of simplify.md
  4. ## Overview
  5. Simplify code by reducing complexity while preserving exact behavior. 2 sentences left out: The overview restates behavior preserved exactly, taken below.
  6. The goal is not fewer lines — it's code that is easier to read, understand, modify, and debug. left out: The goal is not fewer lines gives way to the ladder's one line where it reads without a pause (contradiction 24). R2
  7. Every simplification must pass a simple test: "Would a new team member understand this faster than the original?" left out: The new team member's test restates Boring over clever.
  8. ## When to Use
  9. After a feature is working and tests pass, but the implementation feels heavier than it needs to be
  10. During code review when readability or complexity issues are flagged
  11. When you encounter deeply nested logic, long functions, or unclear names
  12. When refactoring code written under time pressure
  13. When consolidating related logic scattered across files
  14. After merging changes that introduced duplication or inconsistency
  15. **When NOT to use:**
  16. Code is already clean and readable — don't simplify for the sake of it
  17. You don't understand what the code does yet — comprehend before you simplify
  18. The code is performance-critical and the "simpler" version would be measurably slower
  19. You're about to rewrite the module entirely — simplifying throwaway code wastes effort 12 sentences left out: When to use is the habit's opening and the block's row.
  20. ## The Five Principles left out: The five principles' heading gives way to the page's own headings.
  21. ### 1. Preserve Behavior Exactly left out: The first principle's heading drops its number. replaced by line 3 of simplify.md
  22. 4 sentences taken
  23. ### 2. Follow Project Conventions left out: The second principle's heading drops its number. replaced by line 15 of simplify.md
  24. 4 sentences taken
  25. ### 3. Prefer Clarity Over Cleverness
  26. Explicit code is better than compact code when the compact version requires a mental pause to parse.
  27. ```typescript // UNCLEAR: Dense ternary chain const label = isNew ? 'New' : isUpdated ? 'Updated' : isArchived ? 'Archived' : 'Active'; // CLEAR: Readable mapping function getStatusLabel(item: Item): string { if (item.isNew) return 'New'; if (item.isUpdated) return 'Updated'; if (item.isArchived) return 'Archived'; return 'Active'; } ```
  28. ```typescript // UNCLEAR: Chained reduces with inline logic const result = items.reduce((acc, item) => ({ ...acc, [item.id]: { ...acc[item.id], count: (acc[item.id]?.count ?? 0) + 1 } }), {}); // CLEAR: Named intermediate step const countById = new Map<string, number>(); for (const item of items) { countById.set(item.id, (countById.get(item.id) ?? 0) + 1); } ``` 4 sentences left out: Clarity over cleverness restates Boring over clever.
  29. ### 4. Maintain Balance
  30. Simplification has a failure mode: over-simplification.
  31. Watch for these traps:
  32. **Inlining too aggressively** — removing a helper that gave a concept a name makes the call site harder to read
  33. **Combining unrelated logic** — two simple functions merged into one complex function is not simpler 5 sentences left out: The traps of over-simplification restate the ladder's understanding first and Boring over clever.
  34. **Removing "unnecessary" abstraction** — some abstractions exist for extensibility or testability, not complexity left out: An abstraction kept for extensibility loses to No abstractions that weren't explicitly requested (contradiction 25). R2
  35. **Optimizing for line count** — fewer lines is not the goal; easier comprehension is left out: Fewer lines is not the goal gives way to the ladder's one line (contradiction 24). R2
  36. ### 5. Scope to What Changed left out: The fifth principle's heading drops its number. replaced by line 32 of simplify.md
  37. 3 sentences taken
  38. ## The Simplification Process left out: The process's heading gives way to the page's own headings.
  39. ### Step 1: Understand Before Touching (Chesterton's Fence) left out: The first step's heading becomes the page's. replaced by line 36 of simplify.md
  40. 6 sentences taken
  41. ### Step 2: Identify Simplification Opportunities
  42. Scan for these patterns — each one is a concrete signal, not a vague smell:
  43. **Structural complexity:**
  44. | Pattern | Signal | Simplification |
  45. |---------|--------|----------------|
  46. | Deep nesting (3+ levels) | Hard to follow control flow | Extract conditions into guard clauses or helper functions |
  47. | Long functions (50+ lines) | Multiple responsibilities | Split into focused functions with descriptive names |
  48. | Nested ternaries | Requires mental stack to parse | Replace with if/else chains, switch, or lookup objects |
  49. | Boolean parameter flags | `doThing(true, false, true)` | Replace with options objects or separate functions |
  50. | Repeated conditionals | Same `if` check in multiple places | Extract to a well-named predicate function |
  51. **Naming and readability:**
  52. | Pattern | Signal | Simplification |
  53. |---------|--------|----------------|
  54. | Generic names | `data`, `result`, `temp`, `val`, `item` | Rename to describe the content: `userProfile`, `validationErrors` |
  55. | Abbreviated names | `usr`, `cfg`, `btn`, `evt` | Use full words unless the abbreviation is universal (`id`, `url`, `api`) |
  56. | Misleading names | Function named `get` that also mutates state | Rename to reflect actual behavior |
  57. | Comments explaining "what" | `// increment counter` above `count++` | Delete the comment — the code is clear enough |
  58. | Comments explaining "why" | `// Retry because the API is flaky under load` | Keep these — they carry intent the code can't express |
  59. **Redundancy:**
  60. | Pattern | Signal | Simplification |
  61. |---------|--------|----------------|
  62. | Duplicated logic | Same 5+ lines in multiple places | Extract to a shared function |
  63. | Dead code | Unreachable branches, unused variables, commented-out blocks | Remove (after confirming it's truly dead) |
  64. | Unnecessary abstractions | Wrapper that adds no value | Inline the wrapper, call the underlying function directly |
  65. | Over-engineered patterns | Factory-for-a-factory, strategy-with-one-strategy | Replace with the simple direct approach |
  66. | Redundant type assertions | Casting to a type that's already inferred | Remove the assertion | 26 sentences left out: The opportunity tables restate the ladder, the rules and the review step's excess lens.
  67. ### Step 3: Apply Changes Incrementally left out: The third step's heading becomes the page's. replaced by line 52 of simplify.md
  68. 3 sentences taken
  69. A PR that refactors and adds a feature is two PRs — split them. left out: Two PRs become two commits, the split the line runs. replaced by line 54 of simplify.md
  70. 3 sentences taken
  71. **The Rule of 500:** If a refactoring would touch more than 500 lines, invest in automation (codemods, sed scripts, AST transforms) rather than making the changes by hand.
  72. Manual edits at that scale are error-prone and exhausting to review. 2 sentences left out: The rule of 500 loses to the bar of triviality, not repetition (contradiction 26). R2
  73. ### Step 4: Verify the Result
  74. After all simplifications, step back and evaluate the whole:
  75. ``` COMPARE BEFORE AND AFTER: - Is the simplified version genuinely easier to understand? - Did you introduce any new patterns inconsistent with the codebase? - Is the diff clean and reviewable? - Would a teammate approve this change? ```
  76. If the "simplified" version is harder to understand or review, revert.
  77. Not every simplification attempt succeeds. 5 sentences left out: Verifying the result restates the review step that follows the build.
  78. ## Language-Specific Guidance
  79. ### TypeScript / JavaScript
  80. ```typescript // SIMPLIFY: Unnecessary async wrapper // Before async function getUser(id: string): Promise<User> { return await userService.findById(id); } // After function getUser(id: string): Promise<User> { return userService.findById(id); } // SIMPLIFY: Verbose conditional assignment // Before let displayName: string; if (user.nickname) { displayName = user.nickname; } else { displayName = user.fullName; } // After const displayName = user.nickname || user.fullName; // SIMPLIFY: Manual array building // Before const activeUsers: User[] = []; for (const user of users) { if (user.isActive) { activeUsers.push(user); } } // After const activeUsers = users.filter((user) => user.isActive); // SIMPLIFY: Redundant boolean return // Before function isValid(input: string): boolean { if (input.length > 0 && input.length < 100) { return true; } return false; } // After function isValid(input: string): boolean { return input.length > 0 && input.length < 100; } ```
  81. ### Python
  82. ```python # SIMPLIFY: Verbose dictionary building # Before result = {} for item in items: result[item.id] = item.name # After result = {item.id: item.name for item in items} # SIMPLIFY: Nested conditionals with early return # Before def process(data): if data is not None: if data.is_valid(): if data.has_permission(): return do_work(data) else: raise PermissionError("No permission") else: raise ValueError("Invalid data") else: raise TypeError("Data is None") # After def process(data): if data is None: raise TypeError("Data is None") if not data.is_valid(): raise ValueError("Invalid data") if not data.has_permission(): raise PermissionError("No permission") return do_work(data) ```
  83. ### React / JSX
  84. ```tsx // SIMPLIFY: Verbose conditional rendering // Before function UserBadge({ user }: Props) { if (user.isAdmin) { return <Badge variant="admin">Admin</Badge>; } else { return <Badge variant="default">User</Badge>; } } // After function UserBadge({ user }: Props) { const variant = user.isAdmin ? 'admin' : 'default'; const label = user.isAdmin ? 'Admin' : 'User'; return <Badge variant={variant}>{label}</Badge>; } // SIMPLIFY: Prop drilling through intermediate components // Before — consider whether context or composition solves this better. // This is a judgment call — flag it, don't auto-refactor. ``` 7 sentences left out: The TypeScript, Python and React guidance is knowledge consulted for an engineering choice, handed to garden's maintainer. R2
  85. ## Common Rationalizations
  86. | Rationalization | Reality |
  87. |---|---|
  88. | "It's working, no need to touch it" | Working code that's hard to read will be hard to fix when it breaks. Simplifying now saves time on every future change. |
  89. | "Fewer lines is always simpler" | A 1-line nested ternary is not simpler than a 5-line if/else. Simplicity is about comprehension speed, not line count. |
  90. | "I'll just quickly simplify this unrelated code too" | Unscoped simplification creates noisy diffs and risks regressions in code you didn't intend to change. Stay focused. |
  91. | "The types make it self-documenting" | Types document structure, not intent. A well-named function explains *why* better than a type signature explains *what*. |
  92. | "This abstraction might be useful later" | Don't preserve speculative abstractions. If it's not used now, it's complexity without value. Remove it and re-add when needed. |
  93. | "The original author must have had a reason" | Maybe. Check git blame — apply Chesterton's Fence. But accumulated complexity often has no reason; it's just the residue of iteration under pressure. |
  94. | "I'll refactor while adding this feature" | Separate refactoring from feature work. Mixed changes are harder to review, revert, and understand in history. |
  95. ## Red Flags
  96. Simplification that requires modifying tests to pass (you likely changed behavior)
  97. "Simplified" code that is longer and harder to follow than the original
  98. Renaming things to match your preferences rather than project conventions
  99. Removing error handling because "it makes the code cleaner"
  100. Simplifying code you don't fully understand
  101. Batching many simplifications into one large, hard-to-review commit
  102. Refactoring code outside the scope of the current task without being asked 18 sentences left out: The rationalizations and red flags restate the principles as their violations.
  103. ## Verification
  104. After completing a simplification pass:
  105. [ ] All existing tests pass without modification
  106. [ ] Build succeeds with no new warnings
  107. [ ] Linter/formatter passes (no style regressions)
  108. [ ] Each simplification is a reviewable, incremental change
  109. [ ] The diff is clean — no unrelated changes mixed in
  110. [ ] Simplified code follows project conventions (checked against CLAUDE.md or equivalent)
  111. [ ] No error handling was removed or weakened
  112. [ ] No dead code was left behind (unused imports, unreachable branches)
  113. [ ] A teammate or review agent would approve the change as a net improvement 11 sentences left out: The checklist restates the principles and the review step; its CLAUDE.md is the harness's (R21).

The ledger entry

greenline's ledger logs how each skill was made and changed, with a reason for each entry.

2026-10-17 2026-10-17-ponytail-measured-need-and-simplify-first

Builds only on a measured need; reads simplify.md before a refactor

The habit loads for code the request leaves open, builds only on a measured need and reads simplify.md before replacing working code, since QA runs loaded it ahead of its situation and built after measuring no need.

Authorised by
2026-10-17 The operator's card of 2026-10-15 on the QA series, "One fix job after the fifth family", with the delegation of 2026-10-16 whose words finalise the fix job's slices: a start or a habit loads only in the situation its row names, architecture-survey at an orientation and never as one where a change record exists, secrets only with a secret in reach and ponytail before code the request leaves open; a start is named in the record only when it ran; the survey never opens its report; a session with nothing to resume says so and asks for the request; diagnose ranks its hypotheses before the first probe and keeps them ranked; and ponytail builds only on a measured need and reads simplify.md before a refactor
Pages it touched
SKILL.md
Rulings, R1 to R6
  1. The operator's card of 2026-10-15 on the QA series, "One fix job after the fifth family", with the delegation of 2026-10-16 whose words finalise the fix job's slices: a start or a habit loads only in the situation its row names, architecture-survey at an orientation and never as one where a change record exists, secrets only with a secret in reach and ponytail before code the request leaves open; a start is named in the record only when it ran; the survey never opens its report; a session with nothing to resume says so and asks for the request; diagnose ranks its hypotheses before the first probe and keeps them ranked; and ponytail builds only on a measured need and reads simplify.md before a refactor
  2. the operator's rulings of 2026-10-08 on the intake R3 ("everything is good", and "yes go ahead" on the portable forms of R21), the verdicts standing and every contradiction ruled as recommended: one line where it reads without a pause, which "Boring over clever" already bounds (contradiction 24), no abstraction kept for an extensibility nobody requested (25), the bar for automation triviality and not a line count (26), and a test removed only through sweep-tests and its mutation proof (23); the language section of code-simplification garden's, and its "Read CLAUDE.md" the agent instructions file and the repository's conventions under R21
  3. The method items carry the operator's rulings of 2026-10-08 on the intake R3 ("everything is good", and "yes go ahead" on the portable forms of R21), the verdicts standing and every contradiction ruled as recommended: one line where it reads without a pause, which "Boring over clever" already bounds (contradiction 24), no abstraction kept for an extensibility nobody requested (25), the bar for automation triviality and not a line count (26), and a test removed only through sweep-tests and its mutation proof (23); the language section of code-simplification garden's, and its "Read CLAUDE.md" the agent instructions file and the repository's conventions under R21
  4. the operator's rulings of 2026-10-04, "cool then lock everything in": every change has one record its steps write, and a habit writes none of its own
  5. R16 of 2026-10-07, a habit loaded when its situation arises at any step ("update the agents md created by greenline product to mention the kind with the skill table and also prose about when to use what kind skill")
  6. J-59, on the operator's words of 2026-10-09 ('okay then implement all of this'): a gist of at most twelve words on every account whose reason is stated; no text, measure or method changes
4 earlier entries
  1. 2026-10-09 2026-10-09-ponytail-gists

    Every account gets a short gist for the website

  2. 2026-10-08 2026-10-08-ponytail-recut

    Re-cut as a habit on its own spine, five sources grafted

    Pages it touched: SKILL.md, debt.md, simplify.md

  3. 2026-10-07 2026-10-07-ponytail-refresh

    Upstream unchanged; the recipe re-anchors as it stands

  4. 2026-10-05 2026-10-05-ponytail-recipe

    Moves to its recipe byte for byte, nothing changed