You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
HAPI already discovers skills across agent flavors (cli/src/modules/common/skills.ts) and the web composer offers $skillname autocomplete in every session, but the literal \$skill text only does anything for the two agents that have native skill machinery:
Claude (SDK): the Skill tool looks up SKILL.md on demand.
Codex (CLI): ~/.codex/skills/ is folded into the prompt header.
For OpenCode, Gemini, and Cursor the autocomplete still shows skills, but pressing send delivers \$skill to the model as plain text — the backend has no idea what it means, so the skill is silently ignored. That's a quiet UX trap (autocomplete promises something that doesn't fire).
Proposed change
Add a skill_lookup(name) tool to the existing HAPI MCP server (cli/src/claude/utils/startHappyServer.ts:21, the same one that already exposes change_title / display_image). The tool:
accepts the skill name,
runs the same listSkills / SKILL.md read path the web autocomplete already uses,
returns the SKILL.md body (and a small metadata header) so the model can use it inline.
Pair it with a one-line system-prompt addition (e.g. injected via buildHapiMcpBridge's opener for flavors that don't have native skills): "User messages starting with $name refer to a HAPI skill. Call the skill_lookup MCP tool with that name to fetch its body before acting."
Why this approach
Architecturally HAPI already has the MCP bridge — every Codex/OpenCode/Gemini session connects to it and the model already calls change_title etc. through that channel. Skills become a tool call instead of a string substitution, which means:
True lazy loading (only the SKILL.md the model decides to use enters context — unlike inlining everything at send time).
One implementation that works for OpenCode, Gemini, Cursor, and any future ACP-based flavor — no per-flavor expansion path needed.
Doesn't conflict with native handling — Claude (SDK Skill tool) and Codex (skills folder) can keep using their existing paths; this tool is a fallback for flavors that don't have one.
Discoverable — once registered, every flavor with MCP wiring picks it up for free.
Alternative considered
Per-flavor text expansion in the runner (e.g. runOpencode.ts reads SKILL.md when it sees \$skill, inlines into the prompt before backend.prompt). Smaller diff, but no lazy load, and we have to repeat the integration for every non-skill-native flavor.
Out of scope (for now)
Adapting arguments after the skill name. The MCP tool result should include the remaining user text so the model knows what to do; no parsing on the HAPI side.
Skill caching inside the model context across turns — that's a model-side optimisation.
Related
OpenCode: slash commands not working #671 — OpenCode slash command support. While testing that, OpenCode autocomplete showed \$ skills but the model didn't react. This issue is the follow-up for the skills half of the same UX gap.
远程模式无法读取/斜杠命令和$skills #225 (closed) — earlier report that remote mode couldn't see skills; the discovery path is fixed but the invocation path is still flavor-specific.
cli/src/modules/common/skills.ts — existing skill discovery, ready to be reused.
cli/src/claude/utils/startHappyServer.ts:21 — where the new MCP tool would live alongside change_title and display_image.
What problem are you trying to solve?
HAPI already discovers skills across agent flavors (
cli/src/modules/common/skills.ts) and the web composer offers$skillnameautocomplete in every session, but the literal\$skilltext only does anything for the two agents that have native skill machinery:~/.codex/skills/is folded into the prompt header.For OpenCode, Gemini, and Cursor the autocomplete still shows skills, but pressing send delivers
\$skillto the model as plain text — the backend has no idea what it means, so the skill is silently ignored. That's a quiet UX trap (autocomplete promises something that doesn't fire).Proposed change
Add a
skill_lookup(name)tool to the existing HAPI MCP server (cli/src/claude/utils/startHappyServer.ts:21, the same one that already exposeschange_title/display_image). The tool:listSkills/ SKILL.md read path the web autocomplete already uses,Pair it with a one-line system-prompt addition (e.g. injected via
buildHapiMcpBridge's opener for flavors that don't have native skills): "User messages starting with $name refer to a HAPI skill. Call theskill_lookupMCP tool with that name to fetch its body before acting."Why this approach
Architecturally HAPI already has the MCP bridge — every Codex/OpenCode/Gemini session connects to it and the model already calls
change_titleetc. through that channel. Skills become a tool call instead of a string substitution, which means:Alternative considered
Per-flavor text expansion in the runner (e.g.
runOpencode.tsreads SKILL.md when it sees\$skill, inlines into the prompt beforebackend.prompt). Smaller diff, but no lazy load, and we have to repeat the integration for every non-skill-native flavor.Out of scope (for now)
Related
\$skills but the model didn't react. This issue is the follow-up for the skills half of the same UX gap.cli/src/modules/common/skills.ts— existing skill discovery, ready to be reused.cli/src/claude/utils/startHappyServer.ts:21— where the new MCP tool would live alongsidechange_titleanddisplay_image.