ralphctl 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +11 -4
  2. package/THIRD-PARTY-NOTICES.md +65 -2
  3. package/dist/agent-definitions/ralphctl-generator.md +3 -2
  4. package/dist/{cli-P7D6G5NI.mjs → chunk-WAHQPVTG.mjs} +16782 -40661
  5. package/dist/cli-W3M7L4TP.mjs +2772 -0
  6. package/dist/cli.mjs +1 -1
  7. package/dist/launch-VBRTQP4L.mjs +20602 -0
  8. package/dist/manifest.json +16 -3
  9. package/dist/prompts/_partials/autonomous-operation.md +18 -7
  10. package/dist/prompts/_partials/conventions-agents-md.md +2 -2
  11. package/dist/prompts/_partials/conventions-claude-md.md +2 -0
  12. package/dist/prompts/_partials/decisions.md +0 -1
  13. package/dist/prompts/_partials/evaluator-failure-modes.md +8 -5
  14. package/dist/prompts/_partials/evaluator-grading-rules.md +9 -5
  15. package/dist/prompts/_partials/one-shot-operation.md +6 -0
  16. package/dist/prompts/apply-feedback/template.md +5 -4
  17. package/dist/prompts/create-pr/template.md +10 -8
  18. package/dist/prompts/detect-scripts/template.md +7 -4
  19. package/dist/prompts/detect-skills/template.md +2 -0
  20. package/dist/prompts/evaluate/template.md +4 -2
  21. package/dist/prompts/evaluate-continuation/template.md +1 -1
  22. package/dist/prompts/ideate/template.md +2 -3
  23. package/dist/prompts/implement/template.md +21 -14
  24. package/dist/prompts/plan/template.md +3 -4
  25. package/dist/prompts/readiness/template.md +9 -4
  26. package/dist/prompts/refine/template.md +3 -6
  27. package/dist/prompts/reproduce/template.md +7 -0
  28. package/dist/skills/ralphctl-api-and-interface-design/SKILL.md +117 -0
  29. package/dist/skills/ralphctl-code-review-and-quality/SKILL.md +119 -8
  30. package/dist/skills/ralphctl-code-simplification/SKILL.md +100 -0
  31. package/dist/skills/ralphctl-codebase-design/SKILL.md +82 -0
  32. package/dist/skills/ralphctl-debugging-and-error-recovery/SKILL.md +23 -5
  33. package/dist/skills/ralphctl-deprecation-and-migration/SKILL.md +106 -0
  34. package/dist/skills/ralphctl-frontend-ui-engineering/SKILL.md +94 -0
  35. package/dist/skills/ralphctl-humanizer/SKILL.md +137 -0
  36. package/dist/skills/ralphctl-idea-refinement/SKILL.md +2 -0
  37. package/dist/skills/ralphctl-iterative-review/SKILL.md +10 -4
  38. package/dist/skills/ralphctl-observability-and-instrumentation/SKILL.md +104 -0
  39. package/dist/skills/ralphctl-performance-optimization/SKILL.md +123 -0
  40. package/dist/skills/ralphctl-ponytail/SKILL.md +38 -28
  41. package/dist/skills/ralphctl-security-and-hardening/SKILL.md +259 -0
  42. package/dist/skills/ralphctl-source-driven-development/SKILL.md +103 -0
  43. package/dist/skills/ralphctl-spec-driven-development/SKILL.md +148 -0
  44. package/dist/skills/ralphctl-test-driven-development/SKILL.md +29 -2
  45. package/dist/skills/ralphctl-writing-for-agents/SKILL.md +113 -0
  46. package/package.json +10 -10
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: ralphctl-frontend-ui-engineering
3
+ description: UI engineering discipline for user-facing interfaces — follow the project's design system and tokens instead of a generic look, handle loading, empty, error, and permission states, meet accessibility basics (keyboard access, labels, focus, contrast, never colour alone), and keep components focused with data loading separate from presentation. Use when building or changing screens, components, layouts, or interaction states in any UI stack.
4
+ license: MIT
5
+ ---
6
+
7
+ # Frontend UI Engineering
8
+
9
+ > Adapted from [addyosmani/agent-skills — "Frontend UI Engineering"](https://github.com/addyosmani/agent-skills)
10
+ > (MIT). Adapted for ralphctl's harness contract.
11
+
12
+ Build interfaces that look like a design-aware engineer made them for this product: the project's own
13
+ design system, every state handled, usable from a keyboard and a screen reader. The specifics differ by
14
+ stack — a component framework, server-rendered templates, a native toolkit — so learn this project's
15
+ before writing any UI.
16
+
17
+ ## When this applies
18
+
19
+ - **Execute** — whenever the task builds or changes something a user sees or operates. When reviewing a
20
+ UI change, use the self-check below as the lens: a missing state or an inaccessible control is a
21
+ finding, not a nit.
22
+
23
+ ## Discover the UI stack first
24
+
25
+ Find the component library, the theme or token file (colour, spacing, type, radius), the existing
26
+ components that already solve part of the task, and how the project tests UI (component tests,
27
+ accessibility checks, visual or browser tests). Reuse a house component before writing a new one.
28
+
29
+ ## Components
30
+
31
+ - **One job per component.** A component that fetches, transforms, and renders is three things.
32
+ - **Composition over configuration.** A growing list of layout and variant flags signals a component
33
+ that should accept children or slots instead.
34
+ - **Data apart from presentation.** A container loads data and decides which state to show; a
35
+ presentational piece renders what it is given. The presentational piece is then trivial to test.
36
+ - **The simplest state that works.** Local state first; lift it only when siblings share it; a shared
37
+ context for read-mostly app-wide values; the URL for shareable view state (filters, pagination); the
38
+ project's server-data layer for remote data; a global store only for complex client state many places
39
+ share. Use the mechanisms the project already has.
40
+
41
+ ## Follow the design system
42
+
43
+ - Use the project's tokens for colour, spacing, type, and radius — never a raw value off the scale.
44
+ - Keep the type hierarchy: heading levels in order, heading styles only on headings.
45
+ - Use realistic content when building, not placeholder text — real lengths reveal wrapping and overflow.
46
+ - Avoid the generic generated look: a default accent palette on everything, decorative gradients,
47
+ maximal rounding, uniform oversized padding, stock card grids, stacked shadows. Each one ignores the
48
+ product's real hierarchy; the project's system already decided these.
49
+
50
+ ## Handle every state
51
+
52
+ Each view that loads or changes data needs, where it applies:
53
+
54
+ - **Loading** — a placeholder that keeps the layout stable.
55
+ - **Empty** — what this is and the next action, never a blank area.
56
+ - **Error** — what went wrong in plain words and a way to retry.
57
+ - **Partial or not permitted** — what the user can still do.
58
+ - **Success** — feedback that the action happened.
59
+
60
+ Check long and short content, and the narrowest and widest layouts the product supports.
61
+
62
+ ## Accessibility basics
63
+
64
+ - Use native interactive elements (buttons, links, inputs) over clickable generic containers. A custom
65
+ control needs a role, keyboard focus, and the expected key handling.
66
+ - Every control is reachable and operable from the keyboard, in a sensible order.
67
+ - Every input has a label; an icon-only control has an accessible name.
68
+ - Move focus deliberately when content changes — into a dialog when it opens, back when it closes.
69
+ - Text meets WCAG AA contrast (4.5:1 for body text, 3:1 for large text).
70
+ - Never convey state by colour alone; pair it with text or an icon.
71
+
72
+ ## Verification
73
+
74
+ Extend the project's existing UI tests for the new states and controls. When the project has no way to
75
+ check something in this session (a visual check, a screen-reader pass), say what was not verified in a
76
+ `note` signal when the prompt's output-contract section lists it; otherwise fold it into the required
77
+ signal's own fields.
78
+
79
+ ## Red flags
80
+
81
+ - Raw colour or spacing values instead of tokens.
82
+ - A view with no loading, empty, or error state.
83
+ - A clickable element that the keyboard cannot reach.
84
+ - Colour as the only indicator of state.
85
+ - A new component that duplicates one the project already has.
86
+
87
+ ## Self-check
88
+
89
+ - [ ] Uses the project's components and tokens.
90
+ - [ ] Loading, empty, error, permission, and success states are handled where they apply.
91
+ - [ ] Every interactive element works from the keyboard and has an accessible name.
92
+ - [ ] Focus moves correctly when content changes.
93
+ - [ ] Contrast meets AA; no state is conveyed by colour alone.
94
+ - [ ] Works at the narrowest and widest supported layouts.
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: ralphctl-humanizer
3
+ description: Edit prose so it reads like a specific person wrote it while keeping its meaning intact — remove staged contrasts, restating closers, run-up openers, reflexive lists of three, dash-chained clauses, inflated significance, promotional and stock model vocabulary, decorative bold and headings, and chat leftovers, while keeping every fact and the format the output contract requires. Use when writing or revising human-facing text such as a PR description, requirements prose, or a summary.
4
+ license: MIT
5
+ ---
6
+
7
+ # Humanizer
8
+
9
+ > Concept from [blader/humanizer](https://github.com/blader/humanizer) (MIT), which builds on Wikipedia's
10
+ > "Signs of AI writing" guide. The pattern catalogue below is written fresh for ralphctl, not copied.
11
+ > Adapted for ralphctl's harness contract.
12
+
13
+ Generated prose defaults to whatever suits the most readers, so the same safe moves recur in every text.
14
+ Someone writing for a particular reader makes particular choices. This skill strips the defaults and keeps
15
+ the content.
16
+
17
+ ## How this runs here
18
+
19
+ - Apply it while writing the prose your output signal carries. The signal gets only the final text — no
20
+ draft, no list of patterns found, no commentary about the edit.
21
+ - The prompt's output contract wins: keep its required headings, sections, field formats, and literal
22
+ values. Leave code, commands, paths, identifiers, and link targets exactly as they are.
23
+ - Add nothing. No fact, name, number, date, or claim that is not in your source material. If a sentence
24
+ only works with a detail you don't have, simplify the sentence instead.
25
+
26
+ ## When this applies
27
+
28
+ - **Create PR** — the title and the description body.
29
+ - **Refine** — the prose around the requirements. Plain wording never costs a criterion its precision; a
30
+ testable predicate stays testable.
31
+
32
+ ## Method
33
+
34
+ 1. **Spot the patterns.** Go through the full draft and mark each pattern listed below. They also show up
35
+ across sentences and paragraphs: a contrast spread over two sentences counts, and so does every section
36
+ ending on an identical wrap-up line.
37
+ 2. **Rewrite each point plainly.** State it directly. When a paragraph is awkward, restructure it from its
38
+ central point instead of patching phrases. Let sentence length vary.
39
+ 3. **Check the result.** Nothing added, nothing lost. Then look once more for the tells that survive a
40
+ rewrite most often: contrasts, closers, threes, dashes, and bold labels.
41
+
42
+ ## Patterns, strongest first
43
+
44
+ ### Staging instead of saying
45
+
46
+ 1. **Contrast with a claim nobody made.** "This isn't just X — it's Y", "rather than X", a "No, it's
47
+ not…" sentence followed by the real point, a trailing "— no X needed". The negative half inflates the
48
+ positive one. A contrast earns its place if it fixes a misconception your reader really has, or if each
49
+ side tells them something.
50
+ 2. **Closers that restate.** A last short line repeating the paragraph ("That's the whole point."), a
51
+ string of fragments for drama, emphasis by capitals or dotted words. Cut it unless it adds a fact.
52
+ 3. **Borrowed depth.** "At its heart", "the real question is", "X is the currency of Y". Drop the
53
+ aphorism and state the concrete point.
54
+ 4. **Run-ups.** Announcing what comes next ("Here's the thing", "Let's walk through it", "Quick note").
55
+ Start with the content.
56
+ 5. **Answering no one.** "To be clear", "This doesn't mean", "You might think". Remove the defence unless
57
+ the objection is real in context.
58
+
59
+ ### Rhythm by habit
60
+
61
+ 6. **Reflexive threes.** Three items because three sounds complete. Keep three only when there are three
62
+ distinct things.
63
+ 7. **Repeated openings.** Consecutive sentences that open with the same word or phrase. Merge them or
64
+ vary the subject.
65
+ 8. **Dashes as default glue.** Reach for ordinary punctuation first (full stop, comma, colon, brackets) and
66
+ use a dash only when none of those works. Never touch a dash that belongs to code, a command, a path, or
67
+ a URL.
68
+ 9. **Piled hedges.** "Could potentially perhaps". Keep one qualifier where the doubt is real.
69
+
70
+ ### Inflation
71
+
72
+ 10. **Stock model vocabulary.** Words that turn up far more in generated text than in people's: delve,
73
+ seamless, leverage and harness (as figurative verbs), robust (when not technical), crucial, pivotal,
74
+ myriad, realm, tapestry, landscape (abstract), foster, elevate, empower, unlock, streamline,
75
+ showcase, underscore, testament, meticulous, game-changing, cutting-edge. Use the plain word. One on
76
+ its own is weak evidence; a cluster is strong.
77
+ 11. **Inflated significance.** "Marks a turning point", "paves the way", "raises the bar", a closing
78
+ paragraph about what the future holds. Stop once the concrete facts run out.
79
+ 12. **Editorialising -ing tails.** "…, highlighting its importance", "…, ensuring a smooth experience".
80
+ Keep the fact; drop the tail unless the source supports it.
81
+ 13. **Promotional tone.** "Powerful", "effortless", "best-in-class", "beautifully". Say what the thing does.
82
+ 14. **Vague authority.** "Experts agree", "widely regarded". Name the source or drop the claim.
83
+ 15. **Dodging plain verbs.** "Serves as", "functions as", "boasts". Use is and has.
84
+ 16. **Vague links.** "Associated with", "tied to". Name the actual relation, or keep the vague wording
85
+ when the source gives nothing more.
86
+
87
+ ### Formatting by habit
88
+
89
+ 17. **Bold everywhere.** Bold on ordinary words, or a bolded label plus colon at the start of every
90
+ bullet. Remove the bold, and when the labels say nothing, rewrite the list as sentences.
91
+ 18. **Decorated headings.** Title Case, emoji, arrows, a rule between every section. Use sentence case and
92
+ plain headings, unless the contract prescribes the heading text.
93
+
94
+ ### Leftovers
95
+
96
+ 19. **Chat residue.** "I hope this helps", "Great question", "Happy to adjust this", offers to do
97
+ more. Remove the wrapper, keep the content.
98
+ 20. **Writing about the text.** "Below is a summary of", "this description was generated from",
99
+ narrating how the text was assembled. Describing what a change replaces is fine in a PR description —
100
+ that is its subject.
101
+ 21. **Knowledge-limit filler.** Conceding that information is missing, then papering over the hole with
102
+ something that merely sounds right. Say plainly what is unknown, or delete the sentence.
103
+
104
+ ### Wrong reader
105
+
106
+ 22. **Telling the reader what they already know.** A reviewer already has the ticket and the diff. Open with
107
+ the decision and include only the argument that could change their mind about it.
108
+
109
+ ## Before and after
110
+
111
+ Before:
112
+
113
+ > This PR doesn't just fix the retry loop — it fundamentally transforms how we handle 503 responses,
114
+ > ensuring a robust, seamless experience. Retries now stop at the configured limit.
115
+
116
+ After:
117
+
118
+ > Retries on a 503 response now stop at the configured limit instead of looping.
119
+
120
+ Before:
121
+
122
+ > **Performance:** Performance has been improved. **Reliability:** Reliability has been enhanced.
123
+
124
+ After: cut both lines. Neither says what changed; name the concrete changes from the diff instead.
125
+
126
+ ## When not to act
127
+
128
+ Don't rewrite a flagged phrase when it sits in a quotation, a name or title, or a passage about the phrase
129
+ itself. A single tell is weak evidence; act on clusters. Keep what carries a writer's voice — an unusual
130
+ specific detail, mixed feelings, a genuine aside.
131
+
132
+ ## Self-check
133
+
134
+ - [ ] Every fact, number, and name from the source survives; nothing new was added.
135
+ - [ ] The contract's required structure and literal values are untouched.
136
+ - [ ] No staged contrast, restating closer, or run-up remains.
137
+ - [ ] Code, commands, and paths are unchanged.
@@ -17,6 +17,8 @@ worth building — through structured divergent and convergent thinking, not a t
17
17
  - **Ideate** — the primary home: turning a raw prompt or hunch into evaluated, distinct directions.
18
18
  - **Refine** — when the input requirement is really an unshaped idea: run a compressed version of the phases below before writing acceptance criteria.
19
19
 
20
+ **Not for:** a direction that is already chosen and now needs sharp requirements — that is ralphctl-spec-driven-development when installed.
21
+
20
22
  ## Philosophy
21
23
 
22
24
  - Simplicity is the ultimate sophistication. Push toward the simplest version that still solves the real problem.
@@ -8,7 +8,8 @@ description: Cross-phase skill — treat AI output as a controlled feedback loop
8
8
  > Concept
9
9
  >
10
10
  > from [SPDD (Zhang & Xia, martinfowler.com) — "Iterative Review"](https://martinfowler.com/articles/structured-prompt-driven/iterative-review.html).
11
- > Adapted for ralphctl's three phases.
11
+ > Adapted for ralphctl's three phases. Risk-first slicing draws on
12
+ > [addyosmani/agent-skills — "Incremental Implementation"](https://github.com/addyosmani/agent-skills) (MIT).
12
13
 
13
14
  One-shot generation looks fast and is slow. The cheap review you skipped at iteration N becomes the expensive
14
15
  unwind at iteration N+5, when a regression that lived undetected through five steps surfaces only at the
@@ -32,11 +33,16 @@ deployed form — but the same posture also belongs **inside** each phase's work
32
33
 
33
34
  1. **Run the cheapest check first, often.** Lint, typecheck, narrow test runs — not the full suite — after
34
35
  each meaningful change. The point is to catch the regression at the seam, not to certify completion.
35
- 2. **Re-read your own output once before submitting.** Whether it is criteria, tasks, or a diff, the second
36
+ 2. **Slice risk-first, and stay buildable between slices.** When the work has several parts, take the
37
+ least certain one first — the unproven integration, the unfamiliar API — so a dead end surfaces before
38
+ anything is built on it; a plan orders its tasks the same way. When your session can run commands,
39
+ confirm after each slice that the project still builds and its existing checks still pass, so the next
40
+ slice never starts on a broken tree.
41
+ 3. **Re-read your own output once before submitting.** Whether it is criteria, tasks, or a diff, the second
36
42
  read catches what the first one missed. Cheap.
37
- 3. **Treat the check gate as a loop, not a finish line.** A failing gate is feedback, not a verdict. Apply
43
+ 4. **Treat the check gate as a loop, not a finish line.** A failing gate is feedback, not a verdict. Apply
38
44
  the fix and re-run; do not signal completion against a red gate.
39
- 4. **When a fix attempt repeats the same failure, escalate rather than retry.** Two iterations of the same
45
+ 5. **When a fix attempt repeats the same failure, escalate rather than retry.** Two iterations of the same
40
46
  error is a plateau — the next fix is a guess. Surface the blocker rather than burning the budget on a
41
47
  third attempt: write a `note` signal in `signals.json` when the prompt's output-contract section lists
42
48
  it as an accepted kind; when it does not, use whichever blocked or narrative signal the contract does
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: ralphctl-observability-and-instrumentation
3
+ description: Instrument code so its production behaviour can be diagnosed from the outside — start from the questions an operator will ask, then emit structured events with stable names, a correlation id, and an entry-point field, bounded-cardinality metrics with latency percentiles, traces across async boundaries, and symptom-based alerts, never secrets or personal data. Use when adding I/O, retries, queues, background jobs, external integrations, or endpoints, or when a reported problem could not be diagnosed from existing telemetry.
4
+ license: MIT
5
+ ---
6
+
7
+ # Observability and Instrumentation
8
+
9
+ > Adapted from [addyosmani/agent-skills — "Observability and Instrumentation"](https://github.com/addyosmani/agent-skills)
10
+ > (MIT). Adapted for ralphctl's harness contract.
11
+
12
+ Code you cannot observe is code you cannot operate. Instrumentation is written with the feature, the way
13
+ tests are — when it ships without telemetry, the first reported bug becomes archaeology instead of a
14
+ query.
15
+
16
+ **Not for:** diagnosing a failure happening now (ralphctl-debugging-and-error-recovery when installed),
17
+ or optimising measured slowness (ralphctl-performance-optimization when installed).
18
+
19
+ ## When this applies
20
+
21
+ - **Plan** — for tasks that add I/O, retries, queues, jobs, or integrations, put the telemetry in the
22
+ task's steps and add a verification criterion that the failure path is observable. Name the operator
23
+ questions it must answer.
24
+ - **Execute** — instrument as you build, with the logging, metrics, and tracing libraries the project
25
+ already uses. Adding a new telemetry stack is a decision for the task to make, not a side effect.
26
+
27
+ ## 1. Define "working" first
28
+
29
+ Telemetry without a question is noise. Before instrumenting, write down two to four questions an operator
30
+ will ask about this feature — what fraction succeeds first time, why permanent failures fail, whether a
31
+ dependency is slower than usual. Every signal you add must help answer one of them.
32
+
33
+ ## 2. Pick the signal per question
34
+
35
+ | Signal | Answers | Cost |
36
+ | -------------- | ---------------------------------------- | ----------------------------- |
37
+ | Structured log | What happened in this specific case? | Per event; grows with traffic |
38
+ | Metric | How often, how fast, in aggregate? | Fixed per series; cheap |
39
+ | Trace | Where did the time go across components? | Per request; usually sampled |
40
+
41
+ Metrics tell you _that_ something is wrong, traces tell you _where_, logs tell you _why_.
42
+
43
+ ## 3. Structured logging
44
+
45
+ - **Events, not prose.** A stable event name plus machine-readable fields — never a sentence built by
46
+ string interpolation that nobody can query.
47
+ - **Levels used consistently** — error: an invariant broke and someone may need to act; warn: degraded
48
+ but handled (a retry succeeded, a fallback ran); info: a significant business event; debug: diagnostic
49
+ detail, off in production by default.
50
+ - **A correlation id on everything.** Accept or create one at the system boundary and attach it to every
51
+ log line, span, and outbound call, so one request can be reconstructed from interleaved output.
52
+ - **Name the entry point** when several entry points (a scheduler, a replay endpoint, a manual run) feed
53
+ one log. Set it where the run starts and propagate it with the correlation id across the same
54
+ boundaries — queue metadata, headers — rather than re-deriving it downstream.
55
+ - **Never log secrets, tokens, passwords, or full personal data.** Log an allowlist of fields, never a
56
+ whole request body.
57
+
58
+ ## 4. Metrics
59
+
60
+ Instrument rate, errors, and duration for every request-driven endpoint and every external dependency;
61
+ utilisation, saturation, and errors for resources such as pools and queues. Labels come from small fixed
62
+ sets (route template, status class, dependency name) — never user ids, raw URLs, or message text, which
63
+ explode the number of series and belong in logs and traces. Record latency as a histogram and read
64
+ percentiles; an average hides the slowest users.
65
+
66
+ ## 5. Tracing
67
+
68
+ Prefer a vendor-neutral standard such as OpenTelemetry when choosing, and the project's existing setup
69
+ when there is one. Use auto-instrumentation where the stack offers it; add manual spans only around
70
+ meaningful units of work, with the attributes an operator will filter by. Propagate context across every
71
+ async boundary or the trace dies at the gap.
72
+
73
+ ## 6. Alerting
74
+
75
+ Alert on symptoms users feel (error rate, latency, queue age), not causes (CPU, one restart). Every alert
76
+ is actionable, has a threshold and duration justified by an objective or by history, and uses one of two
77
+ severities: act now, or act this week. When the project keeps runbooks, link each new alert to one; do
78
+ not create a runbook location the task did not ask for.
79
+
80
+ ## 7. Verify the telemetry itself
81
+
82
+ Instrumentation is code and can be wrong. Exercise the failure path in a test and assert the emitted
83
+ event and its fields — the project's logger or metrics library usually offers a capture or in-memory
84
+ sink. Checks that need a live environment (a dashboard, a tracing UI, firing an alert) cannot happen in
85
+ this session: list them as unverified in a `note` signal when the prompt's output-contract section lists
86
+ it; otherwise fold them into the required signal's own fields.
87
+
88
+ ## Red flags
89
+
90
+ - A change adding retries, queues, or external calls with no new telemetry.
91
+ - Log lines built by interpolation instead of structured fields.
92
+ - No correlation id, or one shared log fed by several entry points with nothing naming which.
93
+ - Metric labels carrying user ids, raw URLs, or error text.
94
+ - Latency tracked only as an average.
95
+ - Secrets, tokens, or whole request bodies in log output.
96
+
97
+ ## Self-check
98
+
99
+ - [ ] The operator questions are named, and each signal maps to one.
100
+ - [ ] Log output is structured, with stable event names and a correlation id.
101
+ - [ ] No secret or unredacted personal data reaches any log line.
102
+ - [ ] New endpoints and dependencies have rate, error, and duration metrics with bounded labels.
103
+ - [ ] Latency is a histogram with queryable percentiles.
104
+ - [ ] The failure path's telemetry is asserted in a test, or listed as unverified.
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: ralphctl-performance-optimization
3
+ description: Measure-first performance discipline — take a baseline with the project's own tooling, find the actual bottleneck, change one thing, re-measure the same way, and keep the change only when it beats run-to-run noise with the tests still green. Use when a task states a performance target, reports slowness or a regression, or touches a hot path, query, cache, or connection pool; not for speculative optimisation without evidence of a problem.
4
+ license: MIT
5
+ ---
6
+
7
+ # Performance Optimization
8
+
9
+ > Adapted from [addyosmani/agent-skills — "Performance Optimization"](https://github.com/addyosmani/agent-skills)
10
+ > (MIT). Adapted for ralphctl's harness contract.
11
+
12
+ Performance work without measurement is guessing, and guessing adds complexity that costs more than the
13
+ speed it buys. Measure, find the real bottleneck, fix that one thing, measure again — and keep only what
14
+ the numbers justify.
15
+
16
+ **When not to use:** there is no evidence of a problem. Optimising on a hunch is how neutral complexity
17
+ lands.
18
+
19
+ ## When this applies
20
+
21
+ - **Execute** — when the task carries a performance target or a slowness report, or the change touches a
22
+ hot path. The generator measures with the project's tooling; when reviewing, a performance claim with no
23
+ before-and-after numbers behind it is a finding, and so is an "optimisation" that changed behaviour.
24
+
25
+ ## The workflow
26
+
27
+ ```
28
+ MEASURE → IDENTIFY → FIX ONE THING → RE-MEASURE (keep or undo) → GUARD
29
+ ```
30
+
31
+ ### 1. Measure
32
+
33
+ Use what the repository already has — a benchmark target, a profiler, a timing harness, a query-plan
34
+ command, a load script — found in its manifest, scripts, or CI configuration. Fix the budget before you
35
+ start: the same command, the same input, the same conditions (warm or cold cache, sample count). Record
36
+ the baseline numbers.
37
+
38
+ ### 2. Identify
39
+
40
+ Let the symptom pick what to measure first:
41
+
42
+ - **Startup or first load is slow** — payload or bundle size, blocking work at start, slow first
43
+ response.
44
+ - **Interaction feels sluggish** — long synchronous work on the main thread or event loop, redundant
45
+ re-rendering or recomputation.
46
+ - **One operation is slow** — profile it; read the query plan of each query it runs.
47
+ - **Everything slows at once** — connection or thread pool exhaustion, memory pressure, CPU saturation.
48
+ - **Slowness is intermittent** — lock contention, garbage-collection pauses, a slow external dependency.
49
+ - **Memory keeps growing** — leaked references, unbounded caches or lists, retained payloads.
50
+
51
+ ### 3. Fix one thing
52
+
53
+ Fix only the bottleneck step 2 identified. The usual suspects:
54
+
55
+ - **Query per row (N+1).** Fetch the relation in the same query or one batched query, not in the loop.
56
+ - **Unbounded fetching.** Every list read has a limit and a stable order.
57
+ - **A query that ignores its index.** "Add an index" is the guess; the query plan before and after is the
58
+ measurement. A stale row estimate wants refreshed statistics, not a new index. Index for the query's
59
+ shape — equality columns first, then the range or sort column. An index that did not change the plan
60
+ is an undo, and every index taxes every write.
61
+ - **Pool exhaustion.** Every operation slows together and time goes to waiting for a connection. A bigger
62
+ pool only moves the queue somewhere harder to see — find what holds connections, and size pools so the
63
+ total across all processes stays under the server's limit.
64
+ - **Missing or wrong caching.** Cache only what is expensive to produce and read far more often than it
65
+ changes. Every input that changes the result belongs in the key (tenant, locale, permissions, flags) —
66
+ a key that omits the viewer serves one user's data to another. Pick one invalidation strategy and state
67
+ the acceptable staleness. Protect hot keys against a stampede (serve stale while one request
68
+ recomputes, or coalesce concurrent misses). Never cache what must be fresh.
69
+ - **Repeated work in a hot loop.** Hoist the invariant; memoise only what the profile shows is costly.
70
+
71
+ ### 4. Re-measure: keep or undo
72
+
73
+ A fix is a hypothesis until re-measured — the same way as the baseline. Change one thing at a time so the
74
+ number is attributable, and repeat the measurement to compare the delta against run-to-run variance.
75
+
76
+ | Result against the baseline | Action |
77
+ | ----------------------------- | ---------------------------------------- |
78
+ | Beyond the noise, tests green | Keep it. |
79
+ | Within the noise | Undo it. Neutral is not a keep. |
80
+ | Worse | Undo it. |
81
+ | Faster, but a test went red | Undo it — a regression dressed as a win. |
82
+
83
+ Correctness gates the metric: an "optimisation" that wins by skipping work the product needed (a
84
+ validation, a fresh read, an awaited step) is a regression.
85
+
86
+ **Record every attempt, kept and undone alike.** An undone attempt leaves no trace in the diff, which is
87
+ how the same dead idea gets tried again. Record idea, baseline and result, verdict, and why in a `note`
88
+ signal when the prompt's output-contract section lists it; otherwise fold it into the required signal's
89
+ own fields.
90
+
91
+ ### 5. Guard
92
+
93
+ Protect the metric that justified the work. When the project already has a benchmark, performance test,
94
+ or budget, extend it to cover this path. Do not invent a new gate or pipeline step the task did not ask
95
+ for — name the missing guard in the same signal guidance as above instead.
96
+
97
+ ## Common rationalisations
98
+
99
+ | Rationalisation | Reality |
100
+ | ------------------------------------------ | ----------------------------------------------------------------------------------- |
101
+ | "This optimisation is obvious" | If you did not measure, you do not know. Re-measuring an obvious win is cheap. |
102
+ | "The query is slow, add an index" | Read the plan first. The index may exist and be unusable; every index taxes writes. |
103
+ | "Just cache it" | Caching a cheap call buys a staleness bug and nothing else. |
104
+ | "Raise the pool size" | It relocates the queue. Find what holds the connections. |
105
+ | "It didn't help much, but it doesn't hurt" | Neutral changes are maintained forever and bought nothing. Undo them. |
106
+ | "We already wrote it, may as well keep it" | Sunk cost. The measurement does not care how long the change took. |
107
+
108
+ ## Red flags
109
+
110
+ - An optimisation with no profiling data or baseline behind it.
111
+ - Several optimisations measured as one number.
112
+ - An index added without a query plan before and after.
113
+ - A cache key that omits an input the result depends on, or a cache with no stated staleness.
114
+ - A pool size raised in response to exhaustion without finding the holder.
115
+ - A "win" that needed a test changed, skipped, or deleted.
116
+
117
+ ## Self-check
118
+
119
+ - [ ] Before-and-after numbers exist, taken the same way.
120
+ - [ ] The improvement exceeds run-to-run variance.
121
+ - [ ] Changes that did not beat the baseline were undone.
122
+ - [ ] Every attempt is recorded, including the undone ones.
123
+ - [ ] The existing tests still pass — behaviour did not change.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ralphctl-ponytail
3
- description: Anti-over-engineering ladder for choosing HOW to implement something — before writing custom code, climb the rungs in order and stop at the first that holds. Does this need to exist at all (YAGNI) → already in the codebase → standard library → native platform feature → already-installed dependency → one line → minimum code that works. Use when picking an implementation approach or evaluating a new dependency; for keeping the footprint of an already-chosen approach small, defer to the ralphctl-surgical-simplicity skill when installed.
3
+ description: Anti-over-engineering ladder for choosing HOW to implement something — the smallest change that fully solves the task. Before writing custom code, climb the rungs in order and stop at the first that holds. Does this need to exist at all (YAGNI) → already in the codebase → standard library or platform feature → already-installed dependency → one line → minimum code that works. Use when picking an implementation approach or evaluating a new dependency; for keeping the footprint of an already-chosen approach small, defer to the ralphctl-surgical-simplicity skill when installed.
4
4
  license: MIT
5
5
  ---
6
6
 
@@ -11,7 +11,7 @@ license: MIT
11
11
 
12
12
  Be a lazy senior developer. Lazy means efficient, not careless — the posture of someone who has
13
13
  seen every over-engineered codebase and been paged at 3am for one. The best code is the code
14
- never written.
14
+ never written: solve the whole problem with the least new code.
15
15
 
16
16
  ## When this applies
17
17
 
@@ -22,22 +22,27 @@ never written.
22
22
  - **Create PR** — when summarising the change, name what was deliberately skipped and when it
23
23
  would be worth adding.
24
24
 
25
+ ## Before you write
26
+
27
+ Read the task and the code it touches. List every place your change must reach: callers, tests,
28
+ fixtures, config, exports. Check what your change could break for users: data it would destroy or
29
+ expose, callers that stop working. That is scope. Extra features are not.
30
+
25
31
  ## The ladder
26
32
 
27
- Stop at the first rung that holds:
33
+ Stop at the first rung that fully works:
28
34
 
29
- 1. **Does this need to exist at all?** Speculative need = skip it, say so in one line. (YAGNI)
30
- 2. **Already in this codebase?** A helper, util, type, or pattern that already lives here → reuse it. Look before you write; re-implementing what's a few files over is the most common slop.
31
- 3. **Standard library does it?** Use it.
32
- 4. **Native platform feature covers it?** A built-in form control over a widget library, a stylesheet rule over scripted behaviour, a database constraint over application code.
33
- 5. **Already-installed dependency solves it?** Use it. Never add a new one for what a few lines can do.
34
- 6. **Can it be one line?** One line.
35
- 7. **Only then:** the minimum code that works.
35
+ 1. **Does this need to exist at all?** Skip features, options, and flexibility nobody asked for, and say so in one line. (YAGNI) A vague request gets the smallest version that does the core job.
36
+ 2. **Already in this codebase?** A helper, util, type, component, or pattern that already lives here → reuse it, the way the surrounding code does. Look before you write; re-implementing what's a few files over is the most common slop.
37
+ 3. **Standard library or a native platform feature covers it?** Use it — a built-in form control over a widget library, a stylesheet rule over scripted behaviour, a database constraint over application code — unless the project has its own: a house component beats a native widget.
38
+ 4. **Already-installed dependency solves it?** Use it. Never add a new one for what a few lines can do.
39
+ 5. **Can it be one line a reader gets at a glance?** One line.
40
+ 6. **Only then:** the minimum code that works.
36
41
 
37
42
  The ladder is a reflex, not a research project — but it runs _after_ you understand the problem,
38
- not instead of it. Read the task and the code it touches first, trace the real flow end to end,
39
- then climb. Two rungs work → take the higher one and move on. The first lazy solution that works
40
- is the right one — once you actually know what the change has to touch.
43
+ not instead of it. Trace the real flow end to end, then climb. Two rungs work → take the higher
44
+ one and move on. The first lazy solution that works is the right one — once you actually know
45
+ what the change has to touch.
41
46
 
42
47
  **Bug fix = root cause, not symptom.** A report names a symptom. Before you edit, find every
43
48
  caller of the function you're about to touch. The lazy fix IS the root-cause fix: one guard in
@@ -47,26 +52,30 @@ through.
47
52
 
48
53
  ## Rules
49
54
 
50
- - No unrequested abstractions: no interface with one implementation, no factory for one product, no config for a value that never changes.
55
+ - Be lazy about the solution, never about the change itself: finish every part the task needs, including the callers, tests, and fixtures your change breaks.
56
+ - No unrequested abstractions: no interface with one implementation, no factory for one product, no wrapper or type conversion nobody asked for, no config for a value that never changes. Keep values in the form the platform already gives you.
51
57
  - No boilerplate, no scaffolding "for later" — later can scaffold for itself.
58
+ - Keep the structure the codebase already has: its layers, interfaces, and conventions.
52
59
  - Deletion over addition. Boring over clever — clever is what someone decodes at 3am.
53
- - 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.
60
+ - Fewest files possible. Shortest working diff wins — but only once you know everything it must touch. The smallest change in the wrong place isn't lazy, it's a second bug. A one-liner that needs decoding is not short.
61
+ - Code you move or merge keeps its error handling and validation.
62
+ - Comment only the why the code cannot show, in one line.
54
63
  - Complex request? Ship the lazy version and question the rest: "Did X; Y covers it. Need full X? Say
55
64
  so." Write it as a `note` signal in `signals.json` when the prompt's output-contract section lists it,
56
65
  otherwise fold the question into the required signal's own fields. Never stall on an answer you can
57
66
  default.
58
- - Two standard-library options, same size? Take the one that's correct on edge cases. Lazy means writing less code, not picking the flimsier algorithm.
59
- - Mark deliberate simplifications with a `ponytail:` comment (`// ponytail: this exists`) — simple reads as intent, not ignorance. Shortcut with a known ceiling (global lock, O(n²) scan, naive heuristic)? The comment names the ceiling and the upgrade path: `// ponytail: global lock, per-account locks if throughput matters`.
67
+ - Two options of the same size? Take the one that's correct on edge cases. Lazy means writing less code, not picking the flimsier algorithm.
68
+ - A shortcut with a known limit (global lock, O(n²) scan, naive heuristic) gets a code comment naming the limit and the upgrade path, in this form: `// shortcut: global lock, per-account locks if throughput matters`.
60
69
 
61
70
  ## Output
62
71
 
63
- Code first. Keep any accompanying explanation to a few short lines: what was skipped, when to
64
- add it. If the explanation is longer than the code, delete the explanation — every paragraph
65
- defending a simplification is complexity smuggled back in as prose. Explanation the task
66
- explicitly asked for (a report, a walkthrough, per-step notes) is not debt — give it in full;
67
- the rule is only against unrequested prose. Deliberate skips worth remembering: skipped X, add
68
- when Y — as a `note` signal in `signals.json` when the prompt's output-contract section lists
69
- it, otherwise inside the required signal's own fields.
72
+ Code first. Keep any accompanying explanation to one or two short lines: what you skipped or did
73
+ not check, and any risk a reviewer must know. If the explanation is longer than the code, delete
74
+ the explanation — every paragraph defending a simplification is complexity smuggled back in as
75
+ prose. Explanation the task explicitly asked for (a report, a walkthrough, per-step notes) is not
76
+ debt — give it in full; the rule is only against unrequested prose. Deliberate skips and unchecked
77
+ risks worth remembering: skipped X, add when Y — as a `note` signal in `signals.json` when the
78
+ prompt's output-contract section lists it, otherwise inside the required signal's own fields.
70
79
 
71
80
  ## When NOT to be lazy
72
81
 
@@ -82,9 +91,10 @@ up as efficiency and ships a confident wrong fix. Read fully, then be lazy.
82
91
  Hardware is never the ideal on paper: a real clock drifts, a real sensor reads off. Leave the
83
92
  calibration knob, not just less code — the physical world needs tuning a minimal model can't see.
84
93
 
85
- Lazy code without its check is unfinished. Non-trivial logic (a branch, a loop, a parser, a
86
- money/security path) leaves ONE runnable check behind — the smallest thing that fails if the
87
- logic breaks. No frameworks, no fixtures, no per-function suites unless asked. Trivial
88
- one-liners need no test — YAGNI applies to tests too.
94
+ Lazy code without its check is unfinished. New non-trivial logic (a branch, a loop, a parser, a
95
+ money/security path, or a whole new script or app) leaves ONE runnable check behind — one small
96
+ test or an assert-based self-check, the smallest thing that fails if the logic breaks. No
97
+ frameworks, no fixtures, no per-function suites unless asked. Trivial one-liners need no test —
98
+ YAGNI applies to tests too.
89
99
 
90
100
  The shortest path to done is the right path.