Skip to content

Commit 3750536

Browse files
author
Dietrich Gebert
committed
Merge main into fix/uninstall-opencode-flag (keep the Qoder and OpenCode checks)
2 parents b0017e0 + 8b50c44 commit 3750536

41 files changed

Lines changed: 598 additions & 248 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude-plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ponytail",
3-
"version": "5.1.0",
3+
"version": "5.1.1",
44
"description": "Lazy senior dev mode. Forces the simplest, shortest solution that actually works: YAGNI, stdlib first, no unrequested abstractions.",
55
"author": {
66
"name": "Dietrich Gebert",

‎.codex-plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ponytail",
3-
"version": "5.1.0",
3+
"version": "5.1.1",
44
"description": "Lazy senior dev mode. Forces the simplest, shortest solution that actually works: YAGNI, stdlib first, no unrequested abstractions.",
55
"author": {
66
"name": "Dietrich Gebert",

‎.devin-plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ponytail",
3-
"version": "5.1.0",
3+
"version": "5.1.1",
44
"description": "Lazy senior dev mode. Forces the simplest, shortest solution that actually works: YAGNI, stdlib first, no unrequested abstractions.",
55
"author": {
66
"name": "Dietrich Gebert",

‎.github/plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "ponytail",
33
"description": "Lazy senior dev mode. Forces the simplest, shortest solution that actually works: YAGNI, stdlib first, no unrequested abstractions.",
4-
"version": "5.1.0",
4+
"version": "5.1.1",
55
"author": {
66
"name": "Dietrich Gebert",
77
"url": "https://github.com/DietrichGebert"

‎.openclaw/skills/ponytail-debt/SKILL.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ can't quietly become permanent.
1111

1212
## Scan
1313

14-
Grep the repo for comment markers, skipping `node_modules`, `.git`, and build
15-
output:
14+
Grep the repo for comment markers, skipping `.git` and everything the
15+
`.gitignore` files ignore (dependencies, build output, caches, in any stack):
1616

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

1919
If the user names their own marker word (`/ponytail-debt TODO`), grep for that word instead.
2020

‎.opencode/command/ponytail-debt.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
description: "Harvest shortcut: comments into a tracked debt ledger"
33
---
44

5-
Harvest every `shortcut:` comment (and older `ponytail:` ones) 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 --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=build '(#|//|/[*]) ?(shortcut|ponytail):' ., skipping node_modules/.git/build output; if the user names their own marker word, grep for that instead; skip hits that are not a deferral, like a keyboard-shortcut note). One row per marker, grouped by file: <file>:<line>, <what was simplified>. ceiling: <the limit named in the comment>. upgrade: <the trigger to revisit>. 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 shortcut debt. Clean ledger.' Report only, change nothing.
5+
Harvest every `shortcut:` comment (and older `ponytail:` ones) in this repository into a debt ledger so deferrals do not rot into 'later means never'. Grep the whole tree for comment markers (git grep --no-index --exclude-standard -nE '(#|//|/[*]) ?(shortcut|ponytail):', skipping .git and everything .gitignore ignores; if the user names their own marker word, grep for that instead; skip hits that are not a deferral, like a keyboard-shortcut note). One row per marker, grouped by file: <file>:<line>, <what was simplified>. ceiling: <the limit named in the comment>. upgrade: <the trigger to revisit>. 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 shortcut debt. Clean ledger.' Report only, change nothing.

‎.opencode/plugins/ponytail.mjs‎

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
2323
// The shared instruction builder is CommonJS; bridge to it from this ES module.
2424
const require = createRequire(import.meta.url);
2525
const { getPonytailInstructions } = require('../../hooks/ponytail-instructions');
26-
const { getDefaultMode, normalizePersistedMode } = require('../../hooks/ponytail-config');
26+
const { getDefaultMode, normalizeMode, writeDefaultMode } = require('../../hooks/ponytail-config');
2727
const { parseCommandFile, parseSkillFile } = require('./ponytail-frontmatter.cjs');
2828

2929
// OpenCode has no flag-file convention of its own; keep mode beside its config.
@@ -36,7 +36,8 @@ const statePath = path.join(
3636

3737
function readMode() {
3838
try {
39-
return normalizePersistedMode(fs.readFileSync(statePath, 'utf8').trim()) || getDefaultMode();
39+
// review is a one-shot command, never a level (#736); an old saved review falls back.
40+
return normalizeMode(fs.readFileSync(statePath, 'utf8')) || getDefaultMode();
4041
} catch (e) {
4142
return getDefaultMode();
4243
}
@@ -53,9 +54,16 @@ function writeMode(mode) {
5354
// synchronous store if same-turn switching ever matters.
5455
function persistMode(args) {
5556
const wanted = String(args == null ? '' : args).trim();
57+
// `/ponytail default <level>` saves the default for new sessions, like the Claude hook.
58+
const [first, second] = wanted.toLowerCase().split(/\s+/);
59+
if (first === 'default') {
60+
const saved = writeDefaultMode(second);
61+
if (saved) console.log('ponytail default ' + saved);
62+
return;
63+
}
5664
// Bare /ponytail switches ponytail on, or keeps the level when it already is (#639).
5765
if (!wanted && readMode() !== 'off') return;
58-
const mode = wanted ? normalizePersistedMode(wanted) : (getDefaultMode() === 'off' ? 'full' : getDefaultMode());
66+
const mode = wanted ? normalizeMode(wanted) : (getDefaultMode() === 'off' ? 'full' : getDefaultMode());
5967
if (!mode) return;
6068
writeMode(mode);
6169
console.log('ponytail ' + mode);
@@ -101,6 +109,14 @@ function readSkills() {
101109
}
102110
}
103111

112+
// Templates without $ARGUMENTS would drop what the user typed after the
113+
// command (/ponytail-review feature/login), so append it instead.
114+
function withArguments(template, input) {
115+
const text = String(input == null ? '' : input);
116+
if (template.includes('$ARGUMENTS')) return template.replaceAll('$ARGUMENTS', text);
117+
return text.trim() ? template + '\n\n' + text.trim() : template;
118+
}
119+
104120
export default {
105121
id: 'ponytail',
106122

@@ -119,10 +135,14 @@ export default {
119135
description: command.description,
120136
execute: async ({ sessionID, prompt, delivery }) => {
121137
if (command.name === 'ponytail') persistMode(prompt.text);
138+
const withoutMentions = (items) => items?.map(({ mention, ...item }) => item);
122139
await ctx.session.prompt({
123140
...prompt,
124141
sessionID,
125-
text: command.template.replaceAll('$ARGUMENTS', prompt.text || ''),
142+
text: withArguments(command.template, prompt.text),
143+
files: withoutMentions(prompt.files),
144+
agents: withoutMentions(prompt.agents),
145+
skills: withoutMentions(prompt.skills),
126146
delivery,
127147
});
128148
},
@@ -132,11 +152,15 @@ export default {
132152

133153
// Append the ruleset to the system prompt every turn. V2 hands over owned
134154
// system parts, so push one instead of rewriting the tail of another.
135-
await ctx.session.hook('context', (event) => {
155+
// Summary compaction runs its own hook with the same event shape; without
156+
// it the compaction request misses the ruleset and the provider prompt cache.
157+
const addRuleset = (event) => {
136158
const mode = readMode();
137159
if (mode === 'off') return;
138160
event.system.push({ type: 'text', text: getPonytailInstructions(mode) });
139-
});
161+
};
162+
await ctx.session.hook('context', addRuleset);
163+
await ctx.session.hook('compaction', addRuleset);
140164
},
141165

142166
// OpenCode V1: same three behaviors, as hooks on the V1 hook names.

‎.qoder-plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ponytail",
3-
"version": "5.1.0",
3+
"version": "5.1.1",
44
"description": "Lazy senior dev mode. Forces the simplest, shortest solution that actually works: YAGNI, stdlib first, no unrequested abstractions.",
55
"author": {
66
"name": "Dietrich Gebert",

‎INSTALL.md‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,20 +114,25 @@ For full plugin-tier support (automatic mode activation + ruleset injection on e
114114

115115
## Antigravity CLI
116116

117-
Google is renaming Gemini CLI to Antigravity CLI (the `agy` binary); the same extension installs there:
118-
119117
```bash
120118
agy plugin install https://github.com/DietrichGebert/ponytail
121119
```
122120

123-
It reuses this repo's `gemini-extension.json`. One difference: Antigravity converts the `/ponytail` commands into skills, so you type them into the chat (e.g. `/ponytail-review` as a message) instead of picking them from a slash menu. Until the migration completes (around June 18, 2026), `gemini extensions install` still works too. To run it as an always-on rule instead, drop the ruleset into `.agents/rules/`.
121+
Installs the six skills, and Antigravity turns the `/ponytail` commands into skills as well, so you [call them as slash commands](https://www.antigravity.google/docs/skills#slash-command-conversion) such as `/ponytail-review`. No lifecycle hooks, so levels don't persist. For the always-on ruleset, copy [`AGENTS.md`](AGENTS.md) into your project; Antigravity [reads it as workspace rules](https://www.antigravity.google/docs/rules). Install verified with Antigravity CLI 1.3.3.
124122

125123
## Hermes Agent
126124

127125
```bash
128126
hermes plugins install DietrichGebert/ponytail --enable
129127
```
130128

129+
If that stops with `plugin.json declares an unsupported or missing Agent Plugins schema`, it is Hermes' install check (fix pending in [NousResearch/hermes-agent#125937](https://github.com/NousResearch/hermes-agent/pull/125937)). Until it lands, clone the plugin in by hand; Hermes loads it from `plugin.yaml` as usual (verified with Hermes Agent v0.21.7):
130+
131+
```bash
132+
git clone https://github.com/DietrichGebert/ponytail.git ~/.hermes/plugins/ponytail
133+
hermes plugins enable ponytail
134+
```
135+
131136
Restart Hermes after installing. The plugin injects the active Ponytail mode before each LLM turn, registers the bundled skills as `ponytail:<skill>`, and adds `/ponytail`, `/ponytail-review`, `/ponytail-audit`, `/ponytail-debt`, `/ponytail-gain`, and `/ponytail-help`. In shared gateways, restrict `/ponytail` to trusted users with Hermes slash-command access controls; runtime mode is process-local.
132137

133138
## CodeWhale

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ Only install ponytail from `DietrichGebert/ponytail` on GitHub or `@dietrichgebe
164164
| `/ponytail-gain` | Show the measured impact scoreboard (less code, less cost, more speed) from the benchmark. |
165165
| `/ponytail-help` | Quick reference for the commands above. |
166166

167-
Commands need a skill-capable host (Claude Code, Codex, Devin CLI, OpenCode, Gemini, pi, Hermes Agent, Qoder, Grok Build). In Codex CLI and the IDE extension they're skills under the plugin's namespace; invoke with `$ponytail:ponytail-review`. Cursor with the [hooks](INSTALL.md#cursor) gets `/ponytail` level switching only, typed as a plain message. The instruction-only adapters (Cursor's rule file, Windsurf, Cline, Copilot, Kiro, Antigravity) load the always-on ruleset without the commands.
167+
Commands need a skill-capable host (Claude Code, Codex, Devin CLI, OpenCode, Gemini, Antigravity CLI, pi, Hermes Agent, Qoder, Grok Build). In Codex CLI and the IDE extension they're skills under the plugin's namespace; invoke with `$ponytail:ponytail-review`. Cursor with the [hooks](INSTALL.md#cursor) gets `/ponytail` level switching only, typed as a plain message. The instruction-only adapters (Cursor's rule file, Windsurf, Cline, Copilot, Kiro, Antigravity's `AGENTS.md` fallback) load the always-on ruleset without the commands.
168168

169169
## FAQ
170170

0 commit comments

Comments
 (0)