clone

a hermes agent plugin for openspec: tools for spec workflows and a dashboard tab for browsing changes and specs

main
hermes-openspec / openspec / changes / bundled-openspec-orchestration-skills / proposal.md
proposal.md 8.8K source

Bundled OpenSpec workflow skills + CLI passthrough

Summary

Bundle 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.

Motivation

The 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.

Our 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.

The 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.

Layer architecture

┌─────────────────────────────────────────────────────────────┐
│ User                                                        │
│  "propose a change for dark mode"                           │
└─────────────┬───────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────┐
│ Skills (11 upstream workflow prompts)                        │
│  openspec-propose, openspec-apply-change, etc.              │
│  Agent auto-loads when user intent matches description.     │
│  Skills instruct agent to run openspec CLI commands.        │
└─────────────┬───────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────┐
│ CLI interface (two paths, same binary)                      │
│                                                             │
│  openspec_cli tool          terminal tool                   │
│  ├─ Gated by check_fn       ├─ Always available             │
│  ├─ JSON output parsed      ├─ Raw stdout                   │
│  └─ Discoverable in tool    └─ Skills use this by default   │
│     list (agent may prefer                                   │
│     it when available)                                      │
└─────────────┬───────────────────────────────────────────────┘
              │
              ▼
┌─────────────────────────────────────────────────────────────┐
│ openspec CLI binary                                          │
│  (installed separately, not part of plugin)                 │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ Plugin tools (19 existing tools)                            │
│  openspec_context, openspec_show, openspec_spec_diff, etc.  │
│  Different JSON shapes than CLI.                            │
│  Used for: ad-hoc agent queries, dashboard backend.         │
│  NOT used by: upstream skills (they call CLI directly).     │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ Dashboard                                                   │
│  Board, spec browser, change detail                         │
│  Reads from filesystem + git, not from CLI or plugin tools. │
└─────────────────────────────────────────────────────────────┘

Design

Skill bundling

Bundle all 11 upstream skills as-is. The upstream generateSkillContent() produces YAML frontmatter + instructions body. We reproduce this format in skills/<name>/SKILL.md.

Skills 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.

11 skills:

Skill Workflow ID Profile
openspec-propose propose core
openspec-explore explore core
openspec-apply-change apply core
openspec-archive-change archive core
openspec-new-change new expanded
openspec-continue-change continue expanded
openspec-ff-change ff expanded
openspec-verify-change verify expanded
openspec-sync-specs sync expanded
openspec-bulk-archive-change bulk-archive expanded
openspec-onboard onboard expanded

openspec_cli passthrough tool

A new agent tool that wraps the openspec CLI binary:

  • 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.
  • check_fn: Gates on _openspec_bin() is not None (same as existing CLI-backed tools).
  • 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.
  • 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.

Registration

In __init__.py register():

  1. Register all existing tools (unchanged).
  2. Register openspec_cli tool.
  3. Iterate skills/ directory and call ctx.register_skill(name, path) for each SKILL.md.

Layer interface documentation

Add docs/layers.md documenting:

  • What each layer does and who uses it
  • Why skills call the CLI directly (not plugin tools)
  • When to use openspec_cli vs terminal vs plugin tools
  • JSON shape differences between CLI output and plugin tool output

Alternatives considered

  • 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.
  • 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.
  • 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.
  • 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.