Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
File renamed without changes.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,15 @@ Injects the ruleset every turn at the active level; adds the `/ponytail` command

The `./` path resolves against your project's `opencode.json`; to share one checkout across projects, point it at the absolute path of the `.mjs` instead (it finds its `hooks/` and `skills/` relative to its own file).

The slash commands ship in `.opencode/commands/` and are auto-discovered when you run OpenCode from this repo's root. To use them in every project without copying, link them into OpenCode's global commands directory:

```bash
mkdir -p ~/.config/opencode/commands
ln -s "$PWD"/.opencode/commands/*.md ~/.config/opencode/commands/

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$PWD extends to where you run it, not to the root of the repository, it's easy to miss it even if it's written a few lines above. Instead, in the README we could write:

mkdir -p ~/.config/opencode/commands
ln -sf /path/to/ponytail/.opencode/commands/*.md ~/.config/opencode/commands/

I added the -f , because rerunning fails with "File exists" on existing symlinks

/cc @fcmfcm01

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And thanks for the patch! it works in my install

Image

```

Run that once from this repo's root; rerun if a new command is added. Restart OpenCode to pick up the changes.

### Gemini CLI

```bash
Expand Down
2 changes: 1 addition & 1 deletion docs/agent-portability.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ to load in a given agent.
|------|-------|-------|
| Claude Code | `.claude-plugin/`, `commands/`, `hooks/` | Full plugin install with session activation, mode tracking, commands, and statusline support. |
| Codex | `.codex-plugin/plugin.json`, `hooks/hooks.json`, `hooks/`, `skills/` | Plugin install with the same skills plus lifecycle hooks for activation and mode tracking. |
| OpenCode | `.opencode/plugins/ponytail.mjs`, `.opencode/command/`, `hooks/`, `skills/` | Server plugin injects the ruleset each turn via `experimental.chat.system.transform` and persists `/ponytail` switches; reuses the shared instruction builder. |
| OpenCode | `.opencode/plugins/ponytail.mjs`, `.opencode/commands/`, `hooks/`, `skills/` | Server plugin injects the ruleset each turn via `experimental.chat.system.transform` and persists `/ponytail` switches; reuses the shared instruction builder. |
| pi | `pi-extension/`, `skills/`, `hooks/` | Package extension: injects the ruleset each turn through the shared instruction builder and registers the `/ponytail` commands. |
| Gemini CLI | `gemini-extension.json`, `AGENTS.md`, `commands/`, `skills/` | Extension manifest points `contextFileName` at `AGENTS.md` for always-on rules, and reuses the existing `commands/*.toml` and `skills/`, which Gemini CLI auto-discovers. |
| Cursor | `.cursor/rules/ponytail.mdc` | Always-on project rule. |
Expand Down
8 changes: 4 additions & 4 deletions tests/commands.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env node
// Every ponytail command the pi extension registers must also ship as a
// file-based command for the hosts that need one: Claude Code (commands/*.toml,
// which Gemini CLI reuses) and OpenCode (.opencode/command/*.md). /ponytail-help
// which Gemini CLI reuses) and OpenCode (.opencode/commands/*.md). /ponytail-help
// was advertised in the README and the help card but missing both files; this
// guards that drift -- a registered command with no adapter file fails here.

Expand Down Expand Up @@ -29,11 +29,11 @@ test('every registered command ships a Claude commands/*.toml', () => {
}
});

test('every registered command ships an OpenCode .opencode/command/*.md', () => {
test('every registered command ships an OpenCode .opencode/commands/*.md', () => {
for (const name of commands) {
assert.ok(
fs.existsSync(path.join(root, '.opencode', 'command', `${name}.md`)),
`missing .opencode/command/${name}.md`,
fs.existsSync(path.join(root, '.opencode', 'commands', `${name}.md`)),
`missing .opencode/commands/${name}.md`,
);
}
});