1# Bundled OpenSpec workflow skills + CLI passthrough23## Summary45Bundle the 11 upstream OpenSpec workflow skills (`openspec-propose`, `openspec-explore`, `openspec-apply-change`, `openspec-verify-change`, etc.) as Hermes plugin skills, and add an `openspec_cli` passthrough tool that runs `openspec <args> --json` and returns raw CLI output. No slash commands — skills are the interface. Document the layer boundaries between skills, CLI, plugin tools, and dashboard.67## Motivation89The upstream OpenSpec CLI generates workflow skills for 24 AI coding assistants (Claude Code, Cursor, Codex, etc.). Each skill is a structured prompt that instructs the agent to run `openspec` CLI commands directly (`openspec new change`, `openspec status --json`, `openspec instructions apply --change <name> --json`) and follow the returned JSON to author artifacts or implement tasks.1011Our plugin currently has 19 agent tools that wrap a subset of the CLI, but return **different JSON shapes** than the CLI. The upstream skill prompts expect the CLI's raw output format (`applyRequires`, `artifacts`, `contextFiles`, `state`). Forcing skills through our tool wrappers would require rewriting every prompt — a permanent sync burden with zero value gained.1213The right approach is passthrough: bundle the upstream skills as-is, let them call the CLI directly via terminal, and add an `openspec_cli` tool as a clean, gated interface for the agent. Our existing plugin tools remain for ad-hoc queries and the dashboard backend.1415## Layer architecture1617```18┌─────────────────────────────────────────────────────────────┐19│ User │20│ "propose a change for dark mode" │21└─────────────┬───────────────────────────────────────────────┘22 │23 ▼24┌─────────────────────────────────────────────────────────────┐25│ Skills (11 upstream workflow prompts) │26│ openspec-propose, openspec-apply-change, etc. │27│ Agent auto-loads when user intent matches description. │28│ Skills instruct agent to run openspec CLI commands. │29└─────────────┬───────────────────────────────────────────────┘30 │31 ▼32┌─────────────────────────────────────────────────────────────┐33│ CLI interface (two paths, same binary) │34│ │35│ openspec_cli tool terminal tool │36│ ├─ Gated by check_fn ├─ Always available │37│ ├─ JSON output parsed ├─ Raw stdout │38│ └─ Discoverable in tool └─ Skills use this by default │39│ list (agent may prefer │40│ it when available) │41└─────────────┬───────────────────────────────────────────────┘42 │43 ▼44┌─────────────────────────────────────────────────────────────┐45│ openspec CLI binary │46│ (installed separately, not part of plugin) │47└─────────────────────────────────────────────────────────────┘4849┌─────────────────────────────────────────────────────────────┐50│ Plugin tools (19 existing tools) │51│ openspec_context, openspec_show, openspec_spec_diff, etc. │52│ Different JSON shapes than CLI. │53│ Used for: ad-hoc agent queries, dashboard backend. │54│ NOT used by: upstream skills (they call CLI directly). │55└─────────────────────────────────────────────────────────────┘5657┌─────────────────────────────────────────────────────────────┐58│ Dashboard │59│ Board, spec browser, change detail │60│ Reads from filesystem + git, not from CLI or plugin tools. │61└─────────────────────────────────────────────────────────────┘62```6364## Design6566### Skill bundling6768Bundle all 11 upstream skills as-is. The upstream `generateSkillContent()` produces YAML frontmatter + instructions body. We reproduce this format in `skills/<name>/SKILL.md`.6970Skills are generated by the upstream CLI via `openspec init --tools <tool>`. For Hermes, we extract the skill content programmatically (via `openspec init` into a temp dir, or by calling the template functions) and bundle the generated `SKILL.md` files. This ensures we always match the upstream format.7172**11 skills:**7374| Skill | Workflow ID | Profile |75|---|---|---|76| `openspec-propose` | propose | core |77| `openspec-explore` | explore | core |78| `openspec-apply-change` | apply | core |79| `openspec-archive-change` | archive | core |80| `openspec-new-change` | new | expanded |81| `openspec-continue-change` | continue | expanded |82| `openspec-ff-change` | ff | expanded |83| `openspec-verify-change` | verify | expanded |84| `openspec-sync-specs` | sync | expanded |85| `openspec-bulk-archive-change` | bulk-archive | expanded |86| `openspec-onboard` | onboard | expanded |8788### `openspec_cli` passthrough tool8990A new agent tool that wraps the `openspec` CLI binary:9192- **Schema:** `openspec_cli(command: str, workdir: str, json_output: bool = true)` — runs `openspec <command> --json` in the given workdir and returns the raw JSON output.93- **check_fn:** Gates on `_openspec_bin() is not None` (same as existing CLI-backed tools).94- **Handler:** `subprocess.run([exe, *shlex.split(command), "--json"], cwd=workdir)` → returns `{ok, exit_code, stdout, stderr}`. If `json_output` is false, omits `--json` and returns raw text.95- **Why:** Gives the agent a discoverable, gated tool for CLI calls instead of constructing shell commands. Skills default to terminal (upstream prompts say "run `openspec new change`"), but the agent may prefer `openspec_cli` when it's available.9697### Registration9899In `__init__.py` `register()`:1001. Register all existing tools (unchanged).1012. Register `openspec_cli` tool.1023. Iterate `skills/` directory and call `ctx.register_skill(name, path)` for each `SKILL.md`.103104### Layer interface documentation105106Add `docs/layers.md` documenting:107- What each layer does and who uses it108- Why skills call the CLI directly (not plugin tools)109- When to use `openspec_cli` vs terminal vs plugin tools110- JSON shape differences between CLI output and plugin tool output111112## Alternatives considered113114- **Rewrite skills to use plugin tools.** Rejected — plugin tools return different JSON shapes than the CLI. Rewriting every prompt to match our shapes creates a permanent sync burden. The upstream prompts are the product.115- **Generate skills at install time via `openspec init`.** Considered — would always be up-to-date. Rejected for now because `openspec init` targets specific tool directories (`.claude/commands/`, `.cursor/commands/`) and doesn't know about Hermes plugin structure. A Hermes adapter upstream is the ideal long-term solution.116- **Slash commands (`/opsx:*`) as signposts.** Rejected — commands return strings to the user, not to the agent. The agent wouldn't act on the prompt. Skills are the correct Hermes-native mechanism for injecting procedural knowledge.117- **Modify skill instructions to use `openspec_cli` instead of terminal.** Rejected — creates a diff from upstream that must be maintained. Skills work as-is with terminal. The agent can discover and prefer `openspec_cli` on its own.