diff --git a/.openclaw/skills/ponytail-debt/SKILL.md b/.openclaw/skills/ponytail-debt/SKILL.md index 20d4fac..24e06ea 100644 --- a/.openclaw/skills/ponytail-debt/SKILL.md +++ b/.openclaw/skills/ponytail-debt/SKILL.md @@ -23,7 +23,7 @@ the convention out of the ledger. One row per marker, grouped by file: -`:. ceiling: . upgrade: .` +`:, . ceiling: . upgrade: .` The convention is `ponytail: , `, so pull the ceiling and the trigger straight from the comment. Want an owner per row too? add diff --git a/.opencode/command/ponytail-debt.md b/.opencode/command/ponytail-debt.md index 4a024dc..d853778 100644 --- a/.opencode/command/ponytail-debt.md +++ b/.opencode/command/ponytail-debt.md @@ -2,4 +2,4 @@ description: "Harvest ponytail: comments into a tracked debt ledger" --- -Harvest every `ponytail:` comment in this repository into a debt ledger so deferrals do not rot into 'later means never'. Grep the whole tree for comment markers (grep -rnE '(#|//) ?ponytail:' ., skipping node_modules/.git/build output). One row per marker, grouped by file: :. ceiling: . upgrade: . Tag any marker that names no upgrade path or trigger as no-trigger, those rot silently. End with the count of markers and how many lack a trigger. If none: 'No ponytail: debt. Clean ledger.' Report only, change nothing. +Harvest every `ponytail:` comment in this repository into a debt ledger so deferrals do not rot into 'later means never'. Grep the whole tree for comment markers (grep -rnE '(#|//) ?ponytail:' ., skipping node_modules/.git/build output). One row per marker, grouped by file: :, . ceiling: . upgrade: . Tag any marker that names no upgrade path or trigger as no-trigger, those rot silently. End with the count of markers and how many lack a trigger. If none: 'No ponytail: debt. Clean ledger.' Report only, change nothing. diff --git a/README.es.md b/README.es.md index d7914a3..bdd7fdc 100644 --- a/README.es.md +++ b/README.es.md @@ -96,7 +96,7 @@ Flojo, no negligente: la validación en límites de confianza, el manejo de pér El mayor esfuerzo que ponytail te va a pedir: -Los plugins de Claude Code y Codex ejecutan dos pequeños lifecycle hooks de Node.js, así que `node` debe estar en tu PATH (nota para usuarios de Nix/nvm: debe estar en el PATH del shell no-interactivo). Si no lo está, los skills igualmente funcionan — la activación automática simplemente queda en silencio en vez de lanzar un error en cada prompt. +Los plugins de Claude Code y Codex ejecutan dos pequeños lifecycle hooks de Node.js, así que `node` debe estar en tu PATH (nota para usuarios de Nix/nvm: debe estar en el PATH del shell no-interactivo). Si no lo está, los skills igualmente funcionan, la activación automática simplemente queda en silencio en vez de lanzar un error en cada prompt. ### Claude Code @@ -224,7 +224,7 @@ node scripts/check-rule-copies.js npm test ``` -El paquete de skills de OpenClaw (`.openclaw/skills/`) se genera desde `skills/`; ejecuta `node scripts/build-openclaw-skills.js` después de cambiar un skill — la suite de tests falla si está desactualizado. +El paquete de skills de OpenClaw (`.openclaw/skills/`) se genera desde `skills/`; ejecuta `node scripts/build-openclaw-skills.js` después de cambiar un skill, la suite de tests falla si está desactualizado. El benchmark de correctness lanza Python para las verificaciones de email y CSV; se prueba `python3` antes que `python`. Las verificaciones de CSV requieren `pandas` instalado localmente. diff --git a/README.md b/README.md index 7dea3c9..21f5ab0 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ It reuses this repo's `gemini-extension.json`. One difference: Antigravity conve ### CodeWhale -Reads `AGENTS.md` from the project root — zero setup. Copy [`AGENTS.md`](AGENTS.md) to your project, or run `codewhale` from a checkout of this repo. That's it. +Reads `AGENTS.md` from the project root, zero setup. Copy [`AGENTS.md`](AGENTS.md) to your project, or run `codewhale` from a checkout of this repo. That's it. ### OpenClaw diff --git a/benchmarks/README.md b/benchmarks/README.md index b4bd57c..ca475e1 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -6,7 +6,7 @@ Three arms (no skill, [caveman](https://github.com/JuliusBrussee/caveman), ponyt ### Claude (Haiku / Sonnet / Opus) -Requires an Anthropic API key and **Node.js ≥ 22.22.0** (promptfoo's engine constraint — +Requires an Anthropic API key and **Node.js ≥ 22.22.0** (promptfoo's engine constraint, check with `node --version` and upgrade if needed): ```bash diff --git a/benchmarks/agentic/README.md b/benchmarks/agentic/README.md index 0d10ae5..f39d68c 100644 --- a/benchmarks/agentic/README.md +++ b/benchmarks/agentic/README.md @@ -92,11 +92,11 @@ python judge.py --run runs/ # score every workspace's source Fewer lines only counts as a win if the code still does the job. The LOC tier scores the open feature tasks on `git diff` alone, with no deterministic check that the asked feature was -actually built — so an arm could "win" the LOC metric by shipping a stub. This pass closes that +actually built, so an arm could "win" the LOC metric by shipping a stub. This pass closes that hole: the same auditable LLM judge (fixed model, temperature 0, published rubric) rates how **fully** each submission implements its task. Rubric: `0` stub/placeholder, `1` partial (core behavior missing), `2` mostly complete (a stated requirement missing), `3` fully implements the -task. Read it **alongside** the LOC table — a low-LOC arm whose completeness also drops is doing +task. Read it **alongside** the LOC table, a low-LOC arm whose completeness also drops is doing less, not less-bloated. Validated like the over-engineering judge: `--selftest` requires the judge to rank a complete diff --git a/docs/platform-native.md b/docs/platform-native.md index 3770f92..afb4cfe 100644 --- a/docs/platform-native.md +++ b/docs/platform-native.md @@ -60,7 +60,7 @@ Libraries people install that the runtime already ships. | `query-string` / `qs` | `new URLSearchParams(location.search)` | | `lodash.clonedeep` | `structuredClone(obj)` | | `lodash.groupby` | `Object.groupBy(arr, fn)` | -| `lodash.debounce` | — see debounce one-liner below | +| `lodash.debounce` | see debounce one-liner below | | `numeral` / `accounting` | `new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" })` | | `date-fns` format | `new Intl.DateTimeFormat("en-US", { dateStyle: "long" }).format(date)` | | `date-fns` relative time | `new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(-3, "day")` | @@ -97,7 +97,7 @@ Packages that wrap Node built-ins. | `make-dir` | `fs.mkdirSync(path, { recursive: true })` | | `slash` (win paths) | `path.posix` or `path.normalize()` | | `uuid` (v4) | `crypto.randomUUID()` | -| `ms` (parse duration strings) | — keep `ms`, it's genuinely useful and tiny | +| `ms` (parse duration strings) | keep `ms`, it's genuinely useful and tiny | | `is-stream` | `val instanceof stream.Readable` | | `object-assign` | `Object.assign()` / spread | | `array-uniq` | `[...new Set(arr)]` | @@ -119,12 +119,12 @@ Packages that wrap what Python already ships. | `python-dateutil` (basic parsing) | `datetime.fromisoformat()` (Python 3.7+) | | `pytz` | `zoneinfo.ZoneInfo("America/New_York")` (Python 3.9+) | | `attrs` (simple data classes) | `@dataclass` | -| `six` | — drop it, Python 2 is gone | +| `six` | drop it, Python 2 is gone | | `pathlib2` | `pathlib.Path` (built-in since Python 3.4) | | `enum34` | `enum.Enum` (built-in since Python 3.4) | | `typing_extensions` (common types) | `from __future__ import annotations` + built-in generics | | `simplejson` (basic use) | `json` (stdlib) | -| `requests` (simple GET) | `urllib.request.urlopen(url)` — `requests` for anything real | +| `requests` (simple GET) | `urllib.request.urlopen(url)`, `requests` for anything real | | `click` (single command) | `argparse` (stdlib) | | `mergedeep` | `dict \| other_dict` (Python 3.9+) | | `more-itertools` (basic) | `itertools` (stdlib): `chain`, `islice`, `groupby`, `product` | @@ -150,9 +150,9 @@ Things the application layer implements that the database already does. | JSON storage + query | `jsonb` (Postgres) / `JSON_EXTRACT` (SQLite/MySQL) | | UUID generation | `gen_random_uuid()` (Postgres) / `UUID()` (MySQL) | | Timestamps on insert/update | `DEFAULT now()` + trigger or `ON UPDATE CURRENT_TIMESTAMP` | -| Enforce uniqueness | `UNIQUE` constraint — not application-level checks | -| Enforce referential integrity | `FOREIGN KEY` — not application-level checks | -| Enforce value ranges | `CHECK (price > 0)` — not application-level validation | +| Enforce uniqueness | `UNIQUE` constraint, not application-level checks | +| Enforce referential integrity | `FOREIGN KEY`, not application-level checks | +| Enforce value ranges | `CHECK (price > 0)`, not application-level validation | --- @@ -170,4 +170,4 @@ You debug the wrapper. Skip the wrapper. The platform ships with your app for free. -When the native solution is genuinely insufficient (old browser support, edge cases it doesn't handle, ergonomics that matter at scale), the library earns its place. Install it then — not before. +When the native solution is genuinely insufficient (old browser support, edge cases it doesn't handle, ergonomics that matter at scale), the library earns its place. Install it then, not before. diff --git a/examples/README.md b/examples/README.md index 4dacc4e..dc4524f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,6 +1,6 @@ # Examples -Real model output, verbatim from benchmark runs — the same task answered by the same model +Real model output, verbatim from benchmark runs, the same task answered by the same model with no skill (`## Without Ponytail`) and with ponytail (`## With Ponytail`), so you can compare side by side. Model: Claude Haiku 4.5, temperature 1, source `benchmarks/output.json`. diff --git a/examples/csv-sum.md b/examples/csv-sum.md index 6560688..99da7d8 100644 --- a/examples/csv-sum.md +++ b/examples/csv-sum.md @@ -2,9 +2,9 @@ **Task:** "Write Python code that reads sales.csv and sums the 'amount' column." -Verbatim model output from a benchmark run — Claude Haiku 4.5, no-skill arm vs ponytail arm, temperature 1, source `benchmarks/output.json`. Reproduce: `npx promptfoo@latest eval -c benchmarks/promptfooconfig.yaml`. +Verbatim model output from a benchmark run, Claude Haiku 4.5, no-skill arm vs ponytail arm, temperature 1, source `benchmarks/output.json`. Reproduce: `npx promptfoo@latest eval -c benchmarks/promptfooconfig.yaml`. -## Without Ponytail — 20 lines of code +## Without Ponytail, 20 lines of code # Python code to read sales.csv and sum the 'amount' column @@ -57,7 +57,7 @@ except KeyError: - Provides built-in error handling - Efficient for large files -## With Ponytail — 3 lines of code +## With Ponytail, 3 lines of code ```python import csv @@ -66,6 +66,6 @@ total = sum(float(row['amount']) for row in csv.DictReader(open('sales.csv'))) print(total) ``` -Skipped: pandas, error handling, file closing — add when the CSV is large, malformed, or you need more analysis. +Skipped: pandas, error handling, file closing, add when the CSV is large, malformed, or you need more analysis. -**20 → 3 lines of code** — same model, same prompt. +**20 → 3 lines of code**, same model, same prompt. diff --git a/examples/debounce.md b/examples/debounce.md index 829017c..371fc33 100644 --- a/examples/debounce.md +++ b/examples/debounce.md @@ -2,9 +2,9 @@ **Task:** "Add debounce to a search input in vanilla JavaScript. It currently fires an API call on every keystroke." -Verbatim model output from a benchmark run — Claude Haiku 4.5, no-skill arm vs ponytail arm, temperature 1, source `benchmarks/output.json`. Reproduce: `npx promptfoo@latest eval -c benchmarks/promptfooconfig.yaml`. +Verbatim model output from a benchmark run, Claude Haiku 4.5, no-skill arm vs ponytail arm, temperature 1, source `benchmarks/output.json`. Reproduce: `npx promptfoo@latest eval -c benchmarks/promptfooconfig.yaml`. -## Without Ponytail — 116 lines of code +## Without Ponytail, 116 lines of code # Debounce Search Input @@ -190,7 +190,7 @@ searchInput.addEventListener('blur', () => { **Typical keystroke reduction:** 10 characters = 10 API calls → 1-2 API calls with debounce ✅ -## With Ponytail — 10 lines of code +## With Ponytail, 10 lines of code ```javascript const searchInput = document.querySelector('input[type="search"]'); @@ -206,6 +206,6 @@ searchInput.addEventListener('input', (e) => { }); ``` -Skipped: debounce utility function, class wrapper, config object — `setTimeout` + `clearTimeout` is the debounce. Add a utility when you need it on 3+ inputs. +Skipped: debounce utility function, class wrapper, config object, `setTimeout` + `clearTimeout` is the debounce. Add a utility when you need it on 3+ inputs. -**116 → 10 lines of code** — same model, same prompt. +**116 → 10 lines of code**, same model, same prompt. diff --git a/examples/deep-clone.md b/examples/deep-clone.md index 89cbf62..f9b7d3f 100644 --- a/examples/deep-clone.md +++ b/examples/deep-clone.md @@ -28,4 +28,4 @@ const copy = JSON.parse(JSON.stringify(original)); const copy = structuredClone(original); ``` -**1 dependency (or a fragile hack) → 1 built-in.** `structuredClone` handles `Date`, `Map`, `Set`, `ArrayBuffer`, `RegExp`, circular references, and more — everything `JSON.parse/stringify` silently drops. Available in every browser since 2022 and Node.js since v17. Pull lodash in when you need the rest of it, not for one function. +**1 dependency (or a fragile hack) → 1 built-in.** `structuredClone` handles `Date`, `Map`, `Set`, `ArrayBuffer`, `RegExp`, circular references, and more, everything `JSON.parse/stringify` silently drops. Available in every browser since 2022 and Node.js since v17. Pull lodash in when you need the rest of it, not for one function. diff --git a/examples/email-validation.md b/examples/email-validation.md index eb71739..43b05bb 100644 --- a/examples/email-validation.md +++ b/examples/email-validation.md @@ -2,9 +2,9 @@ **Task:** "Write me a Python function that validates email addresses." -Verbatim model output from a benchmark run — Claude Haiku 4.5, no-skill arm vs ponytail arm, temperature 1, source `benchmarks/output.json`. Reproduce: `npx promptfoo@latest eval -c benchmarks/promptfooconfig.yaml`. +Verbatim model output from a benchmark run, Claude Haiku 4.5, no-skill arm vs ponytail arm, temperature 1, source `benchmarks/output.json`. Reproduce: `npx promptfoo@latest eval -c benchmarks/promptfooconfig.yaml`. -## Without Ponytail — 75 lines of code +## Without Ponytail, 75 lines of code # Email Validation Function @@ -142,7 +142,7 @@ if __name__ == "__main__": **Recommendation**: Use the `email-validator` library for production applications, as it properly handles RFC 5321/5322 standards. Use the simple regex version for quick scripts or when you want to avoid dependencies. -## With Ponytail — 3 lines of code +## With Ponytail, 3 lines of code ```python import re @@ -151,6 +151,6 @@ def is_valid_email(email: str) -> bool: return bool(re.match(r'^[^@]+@[^@]+\.[^@]+$', email)) ``` -Skipped: RFC 5322 parser, DNS MX lookup, confirmation email. Add when you actually need to reject `user+tag@sub.domain.co.uk` or catch typos — until then, this catches 99% of "oops I fat-fingered it" cases. +Skipped: RFC 5322 parser, DNS MX lookup, confirmation email. Add when you actually need to reject `user+tag@sub.domain.co.uk` or catch typos, until then, this catches 99% of "oops I fat-fingered it" cases. -**75 → 3 lines of code** — same model, same prompt. +**75 → 3 lines of code**, same model, same prompt. diff --git a/examples/group-by.md b/examples/group-by.md index 71e92da..90d014a 100644 --- a/examples/group-by.md +++ b/examples/group-by.md @@ -32,4 +32,4 @@ const byStatus = Object.groupBy(orders, order => order.status); // → { pending: [...], shipped: [...], delivered: [...] } ``` -**1 dependency (or a reduce) → 1 built-in.** `Object.groupBy` shipped in Chrome 117, Firefox 119, Safari 17.4, Node.js 21. If you need a `Map` instead of a plain object: `Map.groupBy(orders, o => o.status)`. Check your target runtime; if you need IE11 or old Node, the `reduce` one-liner is still the right call — not lodash. +**1 dependency (or a reduce) → 1 built-in.** `Object.groupBy` shipped in Chrome 117, Firefox 119, Safari 17.4, Node.js 21. If you need a `Map` instead of a plain object: `Map.groupBy(orders, o => o.status)`. Check your target runtime; if you need IE11 or old Node, the `reduce` one-liner is still the right call, not lodash. diff --git a/examples/infinite-scroll.md b/examples/infinite-scroll.md index 321faac..039b129 100644 --- a/examples/infinite-scroll.md +++ b/examples/infinite-scroll.md @@ -55,4 +55,4 @@ export function Feed({ items, fetchMore, hasMore }) { } ``` -**1 dependency → 0 dependencies.** `IntersectionObserver` fires only when the sentinel enters the viewport — no scroll event, no throttling, no jank. Ships in every browser. The library wraps exactly this API. +**1 dependency → 0 dependencies.** `IntersectionObserver` fires only when the sentinel enters the viewport, no scroll event, no throttling, no jank. Ships in every browser. The library wraps exactly this API. diff --git a/examples/modal-dialog.md b/examples/modal-dialog.md index 0c970e9..db54e7c 100644 --- a/examples/modal-dialog.md +++ b/examples/modal-dialog.md @@ -37,7 +37,7 @@ export function DeleteModal({ onConfirm, onCancel }) { } ``` -A dependency, a portal, an overlay, a root, a trigger, a content wrapper — to show a box with two buttons. +A dependency, a portal, an overlay, a root, a trigger, a content wrapper, to show a box with two buttons. ## With Ponytail diff --git a/examples/rate-limit.md b/examples/rate-limit.md index 84ebe56..e86cabe 100644 --- a/examples/rate-limit.md +++ b/examples/rate-limit.md @@ -2,9 +2,9 @@ **Task:** "Add rate limiting to my FastAPI endpoint so users can't spam it." -Verbatim model output from a benchmark run — Claude Haiku 4.5, no-skill arm vs ponytail arm, temperature 1, source `benchmarks/output.json`. Reproduce: `npx promptfoo@latest eval -c benchmarks/promptfooconfig.yaml`. +Verbatim model output from a benchmark run, Claude Haiku 4.5, no-skill arm vs ponytail arm, temperature 1, source `benchmarks/output.json`. Reproduce: `npx promptfoo@latest eval -c benchmarks/promptfooconfig.yaml`. -## Without Ponytail — 128 lines of code +## Without Ponytail, 128 lines of code # Rate Limiting in FastAPI @@ -248,9 +248,9 @@ async def test_rate_limit(): # First 5 should be 200, 6th should be 429 ``` -**Recommendation:** Use `slowapi` for most cases—it's the most popular and easiest to implement! 🚀 +**Recommendation:** Use `slowapi` for most cases, it's the most popular and easiest to implement! 🚀 -## With Ponytail — 10 lines of code +## With Ponytail, 10 lines of code ```python from fastapi import FastAPI, HTTPException @@ -267,6 +267,6 @@ async def my_endpoint(request): return {"status": "ok"} ``` -Skipped: custom rate limit logic, Redis, sliding windows — `slowapi` handles it. Add when: you need distributed rate limiting across multiple servers (swap `Limiter` for Redis backend) or per-user limits (add `key_func=lambda r: r.headers.get("authorization")`). +Skipped: custom rate limit logic, Redis, sliding windows, `slowapi` handles it. Add when: you need distributed rate limiting across multiple servers (swap `Limiter` for Redis backend) or per-user limits (add `key_func=lambda r: r.headers.get("authorization")`). -**128 → 10 lines of code** — same model, same prompt. +**128 → 10 lines of code**, same model, same prompt. diff --git a/examples/react-countdown.md b/examples/react-countdown.md index 5bfc8b9..8ad7ccf 100644 --- a/examples/react-countdown.md +++ b/examples/react-countdown.md @@ -2,9 +2,9 @@ **Task:** "Build me a countdown timer component in React that counts down from a given number of seconds." -Verbatim model output from a benchmark run — Claude Haiku 4.5, no-skill arm vs ponytail arm, temperature 1, source `benchmarks/output.json`. Reproduce: `npx promptfoo@latest eval -c benchmarks/promptfooconfig.yaml`. +Verbatim model output from a benchmark run, Claude Haiku 4.5, no-skill arm vs ponytail arm, temperature 1, source `benchmarks/output.json`. Reproduce: `npx promptfoo@latest eval -c benchmarks/promptfooconfig.yaml`. -## Without Ponytail — 267 lines of code +## Without Ponytail, 267 lines of code # React Countdown Timer Component @@ -369,7 +369,7 @@ export function StyledCountdownTimer({ initialSeconds = 60 }) { Choose the version that best fits your needs! -## With Ponytail — 9 lines of code +## With Ponytail, 9 lines of code ```jsx export function CountdownTimer({ seconds }) { @@ -385,6 +385,6 @@ export function CountdownTimer({ seconds }) { } ``` -Skipped: pause/resume, formatted display (mm:ss), sound on zero, styling — add when needed. +Skipped: pause/resume, formatted display (mm:ss), sound on zero, styling, add when needed. -**267 → 9 lines of code** — same model, same prompt. +**267 → 9 lines of code**, same model, same prompt. diff --git a/ponytail-mcp/README.md b/ponytail-mcp/README.md index 3ec48a1..17dc67e 100644 --- a/ponytail-mcp/README.md +++ b/ponytail-mcp/README.md @@ -12,9 +12,9 @@ prompt menu, or that pull context through tools. See issue #70. ## What it exposes -- Prompt `ponytail` — returns the ruleset as a user message. Optional `mode` +- Prompt `ponytail`, returns the ruleset as a user message. Optional `mode` argument: `lite`, `full`, or `ultra`. Omit it to use the configured default. -- Tool `ponytail_instructions` — same text, plus `structuredContent` +- Tool `ponytail_instructions`, same text, plus `structuredContent` (`{ mode, instructions }`), for hosts that pull context via tools or code execution. Read-only. diff --git a/skills/ponytail-debt/SKILL.md b/skills/ponytail-debt/SKILL.md index ba672c8..ecbc0ca 100644 --- a/skills/ponytail-debt/SKILL.md +++ b/skills/ponytail-debt/SKILL.md @@ -26,7 +26,7 @@ the convention out of the ledger. One row per marker, grouped by file: -`:. ceiling: . upgrade: .` +`:, . ceiling: . upgrade: .` The convention is `ponytail: , `, so pull the ceiling and the trigger straight from the comment. Want an owner per row too? add