Skip to content

feat: expose ponytail as MCP prompts, add missing CLI subcommands - #102

Merged
getappz merged 2 commits into
masterfrom
fix/dogfooding-issues
Jul 8, 2026
Merged

feat: expose ponytail as MCP prompts, add missing CLI subcommands#102
getappz merged 2 commits into
masterfrom
fix/dogfooding-issues

Conversation

@getappz

@getappz getappz commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

Found via dogfooding: /ponytail* stopped working as Claude Code slash commands once the DietrichGebert/ponytail marketplace plugin (the only thing registering them) was disabled in favor of agentflare's own hook-based routing. Claude Code validates slash commands against its registry before a prompt ever reaches a hook, so disabling the plugin silently broke /ponytail-review, /ponytail-gain, etc. with "Unknown command" errors.

Fixed the way lean-ctx does it for its own /lean-ctx* commands: register MCP prompts (rmcp::model::Prompt/GetPromptResult — same crate agentflare already depends on) instead of relying on a plugin or static command files.

  • Adds src/mcp_prompts.rs: 8 prompts (ponytail + its 7 sub-skills: review/audit/debt/gain/help/playbook/no-hallucination).
  • Wires list_prompts/get_prompt into AgentflareMcp's ServerHandler impl, enables the prompts capability.
  • ponytail (bare) takes an optional mode argument: empty/status reports current mode, lite|full|ultra switches and returns the mode's skill body, off clears it, anything else reports an error — mirroring the original hook's SwitchAction semantics.
  • Each sub-skill prompt persists the mode switch (ponytail::set_active) then returns the full skill markdown, matching what the dedicated /ponytail-review etc. commands did originally.
  • Adds the two ponytail CLI subcommands (playbook, no-hallucination) that existed in the crate's sub_skills/switcher modules but were never wired to agentflare ponytail <name>, for parity with review/audit/debt/gain.

Test plan

  • cargo build --workspace, cargo test --workspace (195 passed, +5 new)
  • cargo clippy --workspace --all-targets — no new findings
  • End-to-end over raw MCP JSON-RPC: initialize reports the prompts capability, prompts/list returns all 8, prompts/get correctly reports/switches mode and returns full skill content for both the bare ponytail prompt and a sub-skill (ponytail-review)
  • After merge, restart Claude Code with agentflare mcp registered and confirm /ponytail* appear in the slash-command autocomplete

Summary by CodeRabbit

  • New Features
    • Added new CLI actions to access additional built-in skill content.
    • Introduced MCP prompt support, enabling listing of available prompts and retrieval by name (main mode and per-skill prompts).
    • Added improved handling for mode selection, including “off” and unknown mode requests.
  • Bug Fixes
    • Enhanced responses when invalid prompt or mode requests are made, providing more consistent error behavior.

/ponytail* stopped being recognized as valid Claude Code slash commands
once the DietrichGebert/ponytail marketplace plugin (the only thing
registering them) was disabled in favor of agentflare's own routing —
Claude Code validates slash commands against its registry before a
prompt ever reaches a hook, so disabling the plugin silently broke
/ponytail-review, /ponytail-gain, etc.

Fix it the way lean-ctx does for its own /lean-ctx* commands: register
MCP "prompts" (rmcp's Prompt/GetPromptResult, same crate agentflare
already depends on) instead of relying on a plugin or static command
files. Adds src/mcp_prompts.rs with 8 prompts (ponytail plus its 7
sub-skills), wires list_prompts/get_prompt into AgentflareMcp's
ServerHandler impl, and enables the prompts capability.

Also adds the two ponytail CLI subcommands (playbook, no-hallucination)
that existed in the crate's sub_skills/switcher but were never wired
to `agentflare ponytail <name>`, for parity with review/audit/debt/gain.

Verified end-to-end over raw MCP JSON-RPC: initialize reports the
prompts capability, prompts/list returns all 8, prompts/get correctly
reports/switches mode and returns full skill content.
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 08c3821b-0429-4e92-809f-5e388fd55b11

📥 Commits

Reviewing files that changed from the base of the PR and between 7468904 and f707597.

📒 Files selected for processing (1)
  • src/mcp_prompts.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/mcp_prompts.rs

📝 Walkthrough

Walkthrough

Adds MCP prompt listing and retrieval for ponytail modes and sub-skills, wires prompt support into the MCP server, and adds CLI actions for two new ponytail sub-skills.

Changes

MCP Prompts feature

Layer / File(s) Summary
Prompt data and module setup
src/main.rs, src/mcp_prompts.rs
Registers the new mcp_prompts module and defines the ponytail sub-skill mapping.
Prompt listing and dispatch
src/mcp_prompts.rs
Creates the base ponytail prompt, adds ponytail-{skill} prompts, and routes incoming prompt names to the right handler.
Mode and skill prompt handlers with tests
src/mcp_prompts.rs
Implements prompt formatting, mode/status handling, skill lookup, and unit tests for prompt responses.
MCP server wiring
src/mcp_server.rs
Enables prompt capability and exposes list/get prompt handlers that delegate to mcp_prompts.
CLI subcommands for new sub-skills
src/cli/ponytail.rs
Adds Playbook and NoHallucination CLI actions and prints their sub-skill text.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant AgentflareMcp
  participant mcp_prompts
  MCPClient->>AgentflareMcp: list_prompts / get_prompt
  AgentflareMcp->>mcp_prompts: delegate request
  mcp_prompts-->>AgentflareMcp: Prompt result or None
  AgentflareMcp-->>MCPClient: ListPromptsResult / GetPromptResult / invalid_params
Loading

Possibly related PRs

  • getappz/agentflare#85: Adds the playbook sub-skill and mode wiring that this PR exposes through PonytailAction::Playbook and ponytail::sub_skills::SKILL_PLAYBOOK.
  • getappz/agentflare#96: Adds the no-hallucination sub-skill and mode wiring that this PR exposes through PonytailAction::NoHallucination and ponytail::sub_skills::SKILL_NO_HALLUCINATION.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change by mentioning MCP prompts for ponytail and the added CLI subcommands.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/dogfooding-issues

Warning

Tools execution failed with the following error:

Failed to run tools: 13 INTERNAL: Received RST_STREAM with code 2 (Internal server error)


Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/mcp_prompts.rs (1)

12-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add drift-protection test between SUB_SKILLS and ponytail::sub_skills::get.

SUB_SKILLS (names+descriptions) and ponytail::sub_skills::get's match arms must stay in sync, or get_ponytail_skill's unwrap_or_default() silently returns an empty body for a listed prompt. Consider a test asserting ponytail::sub_skills::get(name).is_some() for every SUB_SKILLS entry, plus coverage for the "off" and successful lite/full/ultra switch paths in get_ponytail_mode.

Also applies to: 85-89, 91-135

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mcp_prompts.rs` around lines 12 - 20, Add a drift-protection test to keep
SUB_SKILLS and ponytail::sub_skills::get in sync: for every entry in SUB_SKILLS,
assert that get(name) returns Some so get_ponytail_skill never falls back to an
empty body via unwrap_or_default(). Also add coverage around get_ponytail_mode
for the “off” case and the successful lite/full/ultra switch paths so the
prompt-mode mapping stays locked to the documented modes.
src/mcp_server.rs (1)

314-333: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Blocking file I/O inside async handlers.

get_prompt/list_prompts delegate to mcp_prompts, which does synchronous std::fs reads/writes (via ponytail::active_mode/set_active) directly on the async task. Given the small scope (local dev tool, single flag file), impact is limited, but wrapping the sync calls in tokio::task::spawn_blocking would be more idiomatic if this server ever serves concurrent requests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mcp_server.rs` around lines 314 - 333, The async handlers list_prompts
and get_prompt in mcp_server.rs are calling mcp_prompts functions that do
synchronous file I/O on the async task. Move the blocking work behind
tokio::task::spawn_blocking (or equivalent) and await the result inside
list_prompts and get_prompt so the RequestContext<RoleServer> handlers stay
non-blocking. Keep the existing ListPromptsResult::with_all_items and
ErrorData::invalid_params behavior, just wrap the mcp_prompts::list_prompts and
mcp_prompts::get_prompt calls safely.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mcp_prompts.rs`:
- Around line 74-78: The persistence error from ponytail::set_active is being
ignored, so the mode-switch response can claim success even when the active flag
write fails. Update the mode handling in the relevant match arms in
mcp_prompts::assistant_text flow to handle the Result from ponytail::set_active
explicitly instead of calling .ok(), and surface the I/O failure to the caller
by returning an error/failed response or otherwise preventing the success
message when persistence does not succeed.

---

Nitpick comments:
In `@src/mcp_prompts.rs`:
- Around line 12-20: Add a drift-protection test to keep SUB_SKILLS and
ponytail::sub_skills::get in sync: for every entry in SUB_SKILLS, assert that
get(name) returns Some so get_ponytail_skill never falls back to an empty body
via unwrap_or_default(). Also add coverage around get_ponytail_mode for the
“off” case and the successful lite/full/ultra switch paths so the prompt-mode
mapping stays locked to the documented modes.

In `@src/mcp_server.rs`:
- Around line 314-333: The async handlers list_prompts and get_prompt in
mcp_server.rs are calling mcp_prompts functions that do synchronous file I/O on
the async task. Move the blocking work behind tokio::task::spawn_blocking (or
equivalent) and await the result inside list_prompts and get_prompt so the
RequestContext<RoleServer> handlers stay non-blocking. Keep the existing
ListPromptsResult::with_all_items and ErrorData::invalid_params behavior, just
wrap the mcp_prompts::list_prompts and mcp_prompts::get_prompt calls safely.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 77f888db-d144-4a9d-80b9-0ad1bb7087b6

📥 Commits

Reviewing files that changed from the base of the PR and between 4e249fe and 7468904.

📒 Files selected for processing (4)
  • src/cli/ponytail.rs
  • src/main.rs
  • src/mcp_prompts.rs
  • src/mcp_server.rs

Comment thread src/mcp_prompts.rs Outdated
CodeRabbit: set_active(...).ok() discarded persistence errors, so a
prompt could report a mode switch (or return skill content) even when
the underlying flag-file write failed, leaving reported state
inconsistent with actual state.
@getappz
getappz merged commit 6d0f4b6 into master Jul 8, 2026
9 checks passed
@getappz
getappz deleted the fix/dogfooding-issues branch July 8, 2026 10:46
getappz added a commit that referenced this pull request Jul 8, 2026
Two independent additions to the init component pattern, both aimed
at replacing Claude Code's always-on skill-description listing with
agentflare's on-demand skill_search/skill_load (already merged: #102
exposes them as MCP tools, #103 nudges the model toward them):

- agentflare-mcp: registers agentflare's own MCP server (skill_search/
  skill_load) with claude-code (native `claude mcp add`), cline,
  continue, and opencode — same 4 hosts + same merge_json/
  merge_opencode_mcp/write_if_absent helpers the engram component
  already uses for its own manual-registration branches. Other hosts
  report satisfied until their MCP config format is verified here.

- skill-overrides-sync: Claude Code only (other agents have no
  equivalent per-skill mechanism). Scans every skill agentflare's
  registry knows about (crates/skill-registry gets a new
  Registry::list_all_names(), since search() requires a query and
  there was no "list everything" path) and sets
  settings.json:skillOverrides["<name>"] = "name-only" for any skill
  missing an entry — Claude Code's own mechanism for listing a skill's
  name without its description (verified against the live settings
  schema, not assumed). Never touches a skill the user already
  configured differently. Not consent-gated, so it also re-syncs on
  every session-start as new skills appear, not just during `init`.

crates/skill-registry's `skills_db_path()` was duplicated between
mcp_server.rs and the new component; moved to paths.rs as the single
shared definition.

Verified end-to-end: fresh `agentflare init --agent claude-code`
registered the MCP server (`claude mcp list` shows it connected) and
set 57 skills to name-only in one pass; re-running init is a clean
no-op on both.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant