The skill description was written keyword-first ("use when the user
says lazy / complains about boilerplate"), so a model-invoked host
only loaded it on prompts that hit those words. Plain coding tasks
(add a date picker, write a dedupe function, build a cache, fix a bug)
were skipped, exactly the over-build cases ponytail is best at.
Tested via a skill-router proxy (3 runs, 12 labeled prompts): recall
on coding tasks was 2/6 before, 6/6 after, with precision unchanged at
6/6 (no false fires on non-coding prompts). Fix is one clause naming
coding tasks explicitly plus a negative clause to keep precision.
Trigger descriptions live in two source-of-truth spots, both updated:
skills/ponytail/SKILL.md and the DESCRIPTIONS map in
scripts/build-openclaw-skills.js (.openclaw regenerated). The store
blurbs in the plugin manifests are listing metadata, not triggers, so
they are left alone.
loc.js filtered comments line by line, so /* ... */ block comments whose
continuation lines are not *-aligned had their inner lines counted as code.
A plain indented block comment scored higher than the same code written
JSDoc-style. Strip /* ... */ before the line count so both are equal, and
add loc.test.js to lock the behavior.
Fixes#231
Closes#299. The "does the platform already do this?" rung is especially
rich on Apple platforms, but the doc had no Swift coverage. Adds a
Swift/SwiftUI section in the existing two-table format: SwiftUI controls
and the Swift/framework layer, with library carve-outs kept inline to
match the `ms` / `requests` style already in the doc.
Claude-Session: https://claude.ai/code/session_01MtGgxEbiXPQjqMyXWbnixn
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to #318, which updated only the English README. Bumps the agent badge 14->15, adds a Devin CLI install section before OpenClaw, and lists Devin CLI in the skill-capable host line. Also adds Swival to both host lines, which the translations were already missing.
Follow-up to #274: the merged scheme validation accepts host-less URLs (http://, https://), which then fail opaquely inside urlopen(). Add a minimal netloc check after the existing scheme check, so a missing host is rejected up front with a clear argparse error. Additive; keeps the existing scheme message intact.
Adds `.devin-plugin/plugin.json` so the plugin can be installed with
`devin plugins install DietrichGebert/ponytail`. The skills/ directory
is already at the repo root, which is exactly where Devin expects it.
Registers the new manifest in `scripts/check-versions.js` so it stays
in sync with every other host manifest on release.
Updates README: install/uninstall instructions, badge (14 → 15 agents),
and Devin added to the skill-capable hosts list in Commands.
Generated with [Devin](https://devin.ai)
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replace the flat orange badge with a clickable terminal-style banner
image: the "he's building" sticker, a bold headline, and an orange
JOIN THE WAITLIST call to action. Localized banners for EN/ES/KO.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The blue NOTE callout was too quiet. Replace it with a centered bold
line plus a bright orange "join the waitlist" badge (matches the site),
and add the same banner to the Spanish and Korean READMEs.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Promotes the pre-launch waitlist at ponytail.dev/soon with a NOTE
callout just under the header.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Appends a star-history.com chart (light/dark via <picture>) to the end of
the English, Spanish, and Korean READMEs. Heading follows each file's
convention: translated in Spanish ("Historial de estrellas"), English
elsewhere.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Adds the daily and weekly Trendshift badges to the header badge area of
the English, Spanish, and Korean READMEs. Alt text decoded from %2F to a
plain slash for screen readers.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat: inject ponytail ruleset into subagents via SubagentStart hook
SessionStart additionalContext is parent-thread only, so every Task-spawned
agent ran ponytail-unaware. Add a SubagentStart hook that injects the active
ruleset into each subagent, reusing getPonytailInstructions. Native Claude
needs the hookSpecificOutput JSON form (not raw stdout), so writeHookOutput
grows a SubagentStart branch; readMode exposes the live flag.
Workflow- and team-spawned coverage is undocumented upstream; verify in a
fresh session once installed.
Closes#252
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H1dMag33yz1Kf1jS24Aira
* fix: address QA round 1 — make hook tests hermetic + cover Codex SubagentStart
QA round 1 (panel + deepseek-v4-pro) found two real test issues:
- The new subagent block (and the pre-existing claudeEnv block) used a no-op
`delete env.PLUGIN_DATA`; run() spreads process.env, so a PLUGIN_DATA /
COPILOT_PLUGIN_DATA leaked from the shell would steer writeHookOutput into the
codex/copilot branch and silently mis-fire the native-Claude assertions.
Fixed at the source: neutralize both vars once at the top, like CLAUDE_CONFIG_DIR.
- The Codex SubagentStart branch (claude-codex-hooks.json is shared by both plugin
manifests) had zero coverage. Added a codex-path assertion.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H1dMag33yz1Kf1jS24Aira
* fix: use PowerShell-safe command form for SubagentStart hook
Match the post-#265 'node ...; exit 0' form used by the sibling hooks. The old 'command -v node ... || exit 0' form fails tests/hooks-windows.test.js (POSIX-guard and non-blocking asserts) once this branch merges onto current main.
---------
Co-authored-by: Shane McCarron <shane.mccarron@corvexconnect.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Emeriko <dietrich.gebert@gmail.com>
* docs: add Korean README translation
Add README.ko.md following the README.es.md convention (community
translation note, English as canonical) and link it from README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(ko): sync translation with current README
Bring README.ko.md up to current English: npm install for OpenCode
(@dietrichgebert/ponytail) + npm badge, drop the obsolete ln -sf command-symlink
note (the plugin self-registers commands since #197), add the Swival section and
the Codex two-prompt install note.
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Emeriko <dietrich.gebert@gmail.com>
The plugin registers the /ponytail commands itself now (#197), so the manual
ln -sf workaround is obsolete. Add the npm install snippet + version badge,
and bring README.es.md's OpenCode section up to parity with the English one.
Authenticate the release workflow through GitHub OIDC instead of a long-lived
npm token: no secret to leak or rotate, provenance attached automatically.
Upgrade npm on the runner since OIDC publishing needs npm >= 11.5.1 (Node 22
ships npm 10).
Publish under a scope you own outright instead of opencode-ponytail (which
sits on a third-party npm account). Matches the GitHub handle and repo.
publishConfig.access is already public, which scoped public packages need.
* feat: register slash commands from .opencode/command/*.md
Add parseCommandFile() to read frontmatter-described markdown files
and wire them into opencode's config.command during init.
Extend the config hook to scan .opencode/command/ and register each
.md file as a named slash command.
Update the plugin doc comment to reflect the npm install path
(opencode-ponytail) vs the old relative path.
* chore: rename package to opencode-ponytail
Align package name with npm convention for opencode plugins.
Update keywords to include opencode-plugin and opencode tags.
Fix description back to original correct wording (grammatical
regression introduced during editing).
* chore: add npm metadata and publish workflow
Add author, homepage, repository, bugs, main, exports, files, and
publishConfig fields to package.json for npm publishing.
Add .github/workflows/publish.yml to auto-publish to npm on version
tags (v*) with provenance.
* docs: add npm plugin install for opencode-ponytail
---------
Co-authored-by: Emeriko <dietrich.gebert@gmail.com>
syncStatus guarded setStatus but used theme.fg unguarded, so a Pi host
exposing setStatus without a theme threw TypeError on session_start (and
agent_start/agent_end/setMode). Require both before rendering.
Add tests for the render path (previously untested) and the theme-absent
degradation. Follow-up to #275 / #84.
Add a syncStatus function to Pi extension to display the current
Ponytail mode in the status bar.
The indicator updates upon mode changes and hooks into the agent_start
and agent_end events to display a visual active/inactive state.
This provides the user with clear feedback on the currently active
Ponytail intensity level (lite, full, ultra) without running commands.
Add urllib.parse.urlparse to benchmark-local.py and validate that the
provided --ollama-url uses either the http or https scheme.
Fix arbitrary URI handling where the script could previously access
local files (file://) or other unsupported protocols. If the scheme
is invalid, parser.error is called to exit cleanly with a clear message.
Follow-up to #228 (issue #226):
- README: state that scripts/uninstall.js must run *before* the host
remove command, since the script is itself a plugin file and gets
deleted by the removal (or run it from a separate clone).
- uninstall.js: add a ponytail: comment naming the statusLine match
ceiling — substring match + whole-key delete removes a combined
(e.g. caveman+ponytail) statusline wholesale; upgrade path noted.
- Add trailing newline to the file.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
ClawHub does not sync from GitHub. Each OpenClaw skill is pushed with the
clawhub CLI at its own version, so the published copies can drift from the
repo the same way the plugin manifests did (#260). This adds a one-pass
publisher that pushes every generated .openclaw/skills/ skill at the
package.json version, with --dry-run to preview, and documents it in the
README next to the build step.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix: align all version manifests to 4.8.0 + guard against drift (#260, #262)
The v4.8.0 release shipped with all four plugin manifests still reading
4.7.0, and both package.json files still at the 0.1.0 npm-init default.
So Claude/Codex/Gemini reported 4.7.0 as the latest version (#262) and
the project advertised three different versions at once (#260).
Bump all six version-bearing files to 4.8.0 so they match the release tag:
the four plugin manifests, the root package.json, and ponytail-mcp.
Add scripts/check-versions.js, wired into CI, so this cannot recur. It
asserts every version file shares one pinned X.Y.Z version, and on a
release-tag run that the shared version equals the tag. The existing
mutual-agreement check in tests/gemini-extension.test.js could not catch
this, because all four manifests were stale at 4.7.0 together.
Fixes#260
Refs #262
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: target 4.8.1 for a clean superseding release
v4.8.0 was already tagged with the stale 4.7.0 manifests. Rather than rewrite a published tag, ship the consistent versions as v4.8.1. The CI guard enforces tag == version on the release run. (#260, #262)
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#245 "Dangerously lazy": add an operational "fix the root cause, not the
symptom" directive — grep every caller of the function you touch and fix the
shared function once (the smaller diff). Validated on the agentic benchmark: on
a shared-helper bug-fix trap, baseline fixes the root cause 1/6 while ponytail
does 6/6 on both Sonnet 4.6 (the model the issue was filed on) and Opus 4.8,
verified by reading the produced code. Plain prose ("trace the flow") did not
move it; the actionable, lazy-framed directive did.
#217 "Missing rung": add ladder rung 2 "Already in this codebase? Reuse it,
don't re-write it." Propagated across SKILL.md, AGENTS.md, all agent mirror
copies, the hook fallback, and both READMEs (check-rule-copies passes).
Benchmark: 4 new deterministic quality-tier tasks (reuse-slug, reuse-money,
trace-transfer, trace-amount) with selftest-proven good/bad refs; harness gains
multi-file seed support in --selftest, distinctive-behaviour reuse detection,
and counts in-file __main__/demo() self-checks as test LOC (not source bloat)
for surgical tasks. Full writeup in
benchmarks/results/2026-06-22-issue-245-217-comprehension.md.
Also carries the in-progress todo-null benchmark task already present in the
working tree.
Co-authored-by: Dietrich Gebert <dgebert@Dietrichs-MacBook-Pro.local>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The SessionStart nudge built a statusLine command by interpolating the
plugin's __dirname path into a double-quoted shell string. A clone path
containing shell metacharacters (quotes, &, $, backtick, ;) could break
out when the suggested command later runs via the statusline shell.
Low severity in practice: the path is the install location, so triggering
it requires installing into a maliciously-named directory, i.e. the
attacker already controls the filesystem. Hardening it anyway.
Gate the snippet behind isShellSafe() (allowlist of ordinary path chars,
allowing : \ / for normal Windows and POSIX paths). Unsafe paths fall
back to a manual-setup instruction instead of an embeddable command. An
allowlist beats a per-shell escaper, which is its own edge-case bug farm.
Refs #200
#213 guarded cleanup with a flag + named function + process.once. But
fs.rmSync with force:true already no-ops on a missing path, so the guard
and the explicit end-of-file call are unnecessary. Collapse to a single
process.on('exit') handler.
Refs #204
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Em dashes crept back into examples, docs/platform-native.md, several READMEs,
the ponytail-debt skill, and a command file since 88431de. Replaced with plain
punctuation (commas, matching the house convention), .openclaw mirror
regenerated. Follows 88431de's scope: leaves untouched the vendored caveman
SKILL.md and the dated benchmarks/results/ writeups (historical records).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#163 clarified the audit/review Boundaries scope but reintroduced em dashes,
which this repo deliberately purged (commit 88431de "replace em dashes with
plain punctuation across prose"). Keeps the clearer wording, swaps the em dash
for a period. .openclaw mirrors regenerated; suite green.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#82 added a "Web tasks: rung 3 lookup" section to the always-on ponytail
SKILL.md, about an external `modern-web` CLI most users won't have installed.
It's optional bloat in the always-on ruleset, and it broke CI by leaving the
.openclaw mirror stale.
Reverts the section from skills/ponytail/SKILL.md, the README callout, and
examples/web-platform-lookup.md, then regenerates the .openclaw mirror and
removes the Spanish callout that #174 had mirrored. Suite green (56/56).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>