DietrichGebert/ponytail
There is no long-running application: ponytail is a distribution of instruction text plus small adapter shims that host agents invoke. The runtime core is five CommonJS scripts in hooks/ (config resolution, instruction building, host detection/output, activation, mode tracking, subagent injection) spawned by host lifecycle hooks. Per-host adapters (Claude/Codex plugin manifest + hooks JSON, Copilot hooks JSON, Cursor hooks installer, Gemini extension manifest, OpenCode .mjs plugin, pi extension, Hermes Python plugin, MCP stdio server, and instruction-only rule files) all funnel into the shared instruction builder. State is a single mode flag file plus an optional config.json in the user's home/config dirs. Tests are node:test files at tests/, plus nested suites in pi-extension/test and ponytail-mcp/test, driven by `npm test` and the test.yml GitHub Action.
- The npm package's only entrypoint is the OpenCode plugin module: package.json sets "main" and exports to ./.opencode/plugins/ponytail.mjs.
- The runtime core is five shared CommonJS modules — ponytail-config.js (mode/config resolution), ponytail-instructions.js (ruleset builder), ponytail-runtime.js (host detection, state file, stdout protocol), ponytail-activate.js (SessionStart), ponytail-mode-tracker.js (UserPromptSubmit), ponytail-subagent.js (SubagentStart).
- Claude Code and Codex share one hook map, hooks/claude-codex-hooks.json, wiring SessionStart → ponytail-activate.js, SubagentStart → ponytail-subagent.js, and UserPromptSubmit → ponytail-mode-tracker.js, each run as `node "${CLAUDE_PLUGIN_ROOT}/hooks/…"` with a 5s timeout.
- Host detection is env-var based and order-sensitive: COPILOT_PLUGIN_DATA (or a CLAUDE_PLUGIN_ROOT under .vscode/agent-plugins) → Copilot, PLUGIN_DATA → Codex, QODER_SESSION_ID → Qoder, CURSOR_VERSION → Cursor, otherwise native Claude; each host picks a different stateDir and a different stdout JSON shape.
- The single source of truth for the ruleset is skills/ponytail/SKILL.md; getPonytailInstructions() reads it and strips mode-keyed table rows/example bullets for the active level, falling back to an embedded condensed ruleset if the file is unreadable.
- Runtime state is a per-host flag file named .ponytail-active holding the mode string (e.g. ~/.claude/.ponytail-active, $PLUGIN_DATA/.ponytail-active, ~/.cursor/.ponytail-active, ~/.qoder/.ponytail-active); an absent flag means ponytail is off.
- User configuration resolves in order: PONYTAIL_DEFAULT_MODE env var, then defaultMode in $XDG_CONFIG_HOME/ponytail/config.json (~/.config/ponytail or %APPDATA%\ponytail), then the built-in 'full'.
- The OpenCode adapter is a server plugin that registers slash commands from .opencode/command/*.md, adds skills/ to config.skills.paths, appends the ruleset via the experimental.chat.system.transform hook, and persists /ponytail switches in command.execute.before to ~/.config/opencode/.ponytail-active.
- The pi adapter (pi-extension/index.js) registers six slash commands, paints a status-bar indicator via ctx.ui.setStatus, persists session mode through pi.appendEntry('ponytail-mode'), and prepends the ruleset in the before_agent_start event.
- The Hermes adapter is the root __init__.py Python plugin: register() exposes the six skills, hooks pre_llm_call for ruleset injection and pre_gateway_dispatch to rewrite authorized /ponytail-* gateway commands into agent prompts.
- ponytail-mcp is a private, internal-only MCP stdio server that serves the same ruleset as a 'ponytail' prompt and a 'ponytail_instructions' tool, reusing hooks/ponytail-instructions.js via createRequire.
- Instruction-only hosts get verbatim copies of the compact ruleset: .cursor/rules/ponytail.mdc, .windsurf/rules/ponytail.md, .clinerules/ponytail.md, .agents/rules/ponytail.md, .qoder/rules/ponytail.md, .github/copilot-instructions.md, .kiro/steering/ponytail.md — all byte-compared against AGENTS.md by scripts/check-rule-copies.js.
- Build/test: `npm test` runs `node --test tests/*.test.js` then the nested pi-extension and ponytail-mcp suites; CI (.github/workflows/test.yml) additionally runs check-rule-copies.js and check-versions.js on Node 22 / Python 3.12. Release is `npm publish` via publish.yml using OIDC trusted publishing, no token.
- Deployment shape is per-host plugin manifests: .claude-plugin/, .codex-plugin/, .devin-plugin/, .github/plugin/ (Copilot), .qoder-plugin/, .grok-plugin/marketplace.json, .agents/plugins/marketplace.json, gemini-extension.json, plugin.yaml (Hermes), .openclaw/skills/ (ClawHub), and the pi package block in package.json.