agentleFS
mcabreradevmcabreradev/hermes-sdd-agency/skills/software-development/openspec-sdd/SKILL.md

openspec-sdd

Skill1 starsChanged 56 days agoMITView on GitHub

Use when doing spec-driven work with OpenSpec.

  • Installs packages

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Write each artifact to resolvedOutputPath using template as the structure.

    line 103

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

OpenSpec — the full spec-driven loop

OpenSpec (Fission-AI, MIT, @fission-ai/openspec) keeps specs, changes and archive files in openspec/ inside each project. The CLI is the source of truth; the openspec-* skills are generated by it and drive each phase. This skill is the orchestrator: which phase, in which order, against which root.

Invocation in Hermes

Hermes gets skills, not slash commands (OpenSpec has no Hermes command adapter). Invoke them by skill name — and the names are NOT the workflow ids:

PhaseSkill to load
think / scope/openspec-explore
propose (all artifacts at once)/openspec-propose
step-by-step scaffolding/openspec-new-change, /openspec-continue-change, /openspec-ff-change
implement tasks/openspec-apply-change
check code against spec/openspec-verify-change
keep change open, update main specs/openspec-sync-specs, /openspec-update-change
finish/openspec-archive-change, /openspec-bulk-archive-change
adopt in an existing codebase/openspec-onboard

Other tools spell the same phases differently — read the file the CLI wrote, not the canonical name: Claude Code /opsx:propose, Cursor /opsx-propose, Codex $openspec-propose, Gemini CLI /opsx:propose (.toml).

The loop

  idea
   |
   v
 [explore]------> thinking partner; never writes code
   |
   v
 [propose]------> proposal.md + specs/<cap>/spec.md + design.md + tasks.md
   |              (planning ONLY - stop when artifacts exist)
   v
 [apply]--------> implement tasks/*, tick `- [ ]` -> `- [x]` as each one lands
   |
   v
 [verify]-------> code vs spec; do not claim done without running it
   |
   v
 [archive]------> merges delta specs into openspec/specs/, then
                  openspec/changes/archive/YYYY-MM-DD-<name>/

Rules the workflows themselves enforce — respect them, don't work around them:

  • propose authorizes planning only. Even if the request says "build it", it stops after the artifacts. Implementation is a NEW user request via apply.
  • Never create openspec/changes/<name>/ by hand. The CLI scaffold (openspec new change "<name>") writes required metadata (.openspec.yaml).
  • explore never writes code — it may write change artifacts within a confirmed scope, nothing else.
  • Only mark - [x] when the specified behavior is fully implemented, not when deferred or partially done. The apply skill pauses on added scope instead of silently narrowing it.
  • Archive syncs main specs inline; never archive while a sync is in flight.
  • When an implementation is finished and verified, ASK the user before archiving + syncing. The user's standing rule: close the loop by requesting permission ('¿archivo el change y sincronizo los specs?') — archive/sync is the final visible action of the loop, never a silent tail. Also check the work was actually spec-driven first: if the change dir doesn't exist for the work (e.g. an ad-hoc fee policy PR), say so instead of inventing an archive.

Pick the right root first

OpenSpec acts on the nearest openspec/ root from the current directory, so cwd decides what you touch. Before any phase:

cd <project-root>              # where its openspec/ lives
openspec context --json        # returns root.path, or no_openspec_root
openspec list --json           # active changes (work in flight)
openspec list --specs --json   # durable capabilities that already exist
openspec status --change "<name>" --json

openspec list never shows specs; --specs does. Read a spec in full with openspec show "<cap>" --type spec before deciding it is already covered.

In a non-interactive session (no TTY) prefer the scriptable path over the interactive openspec view dashboard:

openspec new change "<name>"                             # scaffold (never mkdir)
openspec status --change "<name>" --json                 # schemaName, applyRequires, artifacts, changeRoot, planningHome
openspec instructions <artifact-id> --change "<name>" --json   # template + instruction + resolvedOutputPath
openspec instructions apply --change "<name>" --json     # contextFiles, progress, tasks, state
openspec validate --all
openspec archive "<name>" --yes

Write each artifact to resolvedOutputPath using template as the structure; context and rules from the instruction JSON are constraints, never content to copy in. state from instructions apply is blocked / ready / all_done. A design.md is conditional (skip when there are no real decisions); specs is only "skipped" via skip_specs in .openspec.yaml, never by judgment.

For standalone spec repos registered on the machine, openspec store list --json and then keep --store <id> on every applicable command (sticky for the session).

This machine's setup

  • CLI: ~/.local/bin/openspec (npm global, node v26) — v1.13.0. An older 1.7.0 still exists under nvm v22.22.2; PATH prefers ~/.local/bin.
  • Profile: custom with all 12 workflows (core ships only 6 and omits verify). openspec config list to check; openspec config profile core reverts. openspec config set workflows rejects a comma string — it needs a JSON array, so edit ~/.config/openspec/config.json and re-run openspec update.
  • Hermes surfaces them via skills.external_dirs, entry ~/.hermes/openspec-global/.hermes/skills (that dir is an openspec inited root, purely a skills carrier). Each project also has its own .hermes/skills from openspec init --tools hermes — same 12 names, so the index shows no duplicates. Local-dir skills win collisions.
  • Projects initialized: <project-root>/filter (a git root) and <project-root>/gatekeepr. gatekeepr's root is NOT a git repo (tga-backend/ and tga-frontend/ are), so Hermes never auto-loads its project skills — the global set is what makes the loop work there.
  • Updating: npm install -g @fission-ai/openspec@latest, then openspec update inside EVERY root (global carrier + each project). Skill count is profile- and delivery-dependent: update regenerates exactly the selected workflows.

Verification gates the repo adds on top of OpenSpec

A change can be fully implemented and still fail its own push. gatekeepr's husky hooks run eslint + tsc --noEmit per commit, and per push tsc --noEmit -p tsconfig.test.json plus a diff-scoped test run. That last one is stricter than the typecheck script and catches test-file-only type errors — e.g. import.meta.dir is rejected there (TS1343) while bun run typecheck passes; use __dirname in test files needing a path. Run the repo's own gate (bun run typecheck:test, bun run format:check) before committing instead of discovering it in the pre-push hook.

  • openspec archive does not run prettier. The archived change dir and the new/updated main specs are written as-is; running bun run format afterwards and amending the commit is normal, and CI's format:check will flag it otherwise (measured on gatekeepr PR #86: 7 spec files missing the trailing newline).
  • In GitHub Actions, a bare binary name in run: fails with exit 127 because node_modules/.bin is not on PATH there; other jobs invoke bins via bun/npm scripts. Use bunx <bin> (resolves the installed devDependency) or bun run <script>.
  • A merged PR with a base that never reached main is a ghost merge. Squashing PR B onto PR-branch A, then squashing A into main onto a different sha, orphans B: gh pr view 89 --json mergedAt says MERGED while git merge-base --is-ancestor <merge-sha> origin/main is false, and B's whole diff is missing from the tree. Verify every "merged" PR once against origin/main (ancestor check + git cat-file -e origin/main:<file> for its listed files) instead of trusting the GitHub state; recover from the original commit (git checkout <commit> -- <files>) when found missing. gatekeepr lost its whole P2 (request correlation, RED metrics, circuit breaker) this way and it was only noticed by cross-checking a follow-up task against the tree.

Pitfalls verified on this machine

  • A main spec that begins with a delta header is silently inert. openspec/specs/<cap>/spec.md whose first line is ## ADDED Requirements (a delta archived into the main spec by mistake) makes that capability's requirements invisible to validate, list and archive — and archive REFUSES any later change that MODIFIES that capability ("target spec is structurally invalid"). Detect with grep -rl "^## ADDED Requirements" openspec/specs/*/spec.md; fix by replacing the delta header with ## Purpose + ## Requirements. gatekeepr had 14 of 75 specs in this state.
  • openspec validate <change> passes while archive would still refuse the delta. Validation of a change does not check that MODIFIED requirement headers exist in the target spec — that surfaces only as an ℹ [INFO] ... Archive would refuse this delta line. Read those INFO lines, not just the pass/fail verdict, before promising a change is archivable. The same applies to using ## MODIFIED Requirements for a requirement that does not yet exist in the target spec: it must be ## ADDED Requirements.
  • Archiving a change that CREATES a capability leaves the new main spec with ## Purpose\nTBD - created by archiving change <name>. Update Purpose after archive. — write the real purpose right after archiving, or the spec stays unfinished forever.
  • openspec validate with no argument prints "Nothing to validate" and exits 1 non-interactively; use openspec validate --all, --changes, --specs or --archived.
  • Exit code IS a verdict in 1.13.0: any ERROR ⇒ 1, all valid ⇒ 0 (measured). But WARNINGs don't change it and ℹ [INFO] lines ("Archive would refuse this delta") appear inside a valid change — read summary.totals + items[].issues[].level, not just the exit.
  • --all / --changes cover only ACTIVE changes plus specs; archived changes are covered by --archived. Passing an archived name in position (validate "2026-01-01-<name>" --type change) resolves the archive dir and reports a FALSE "No deltas found" ERROR.
  • A new capability whose delta carries ## Purpose keeps that Purpose after archiving; without it, the main spec gets Purpose: TBD - created by archiving change <name> (measured). Putting Purpose in the delta is the cheap way to avoid the post-archive edit.
  • skip_specs: true in .openspec.yaml validates a delta-less change with an INFO; it is the legitimate path for refactors/tooling/docs, not an escape hatch from writing scenarios.
  • An inert main spec (first line a delta header) is NOT silent: validate --specs fails it with a missing-Purpose/Requirements ERROR and openspec list --specs --json shows requirementCount: 0 — detect by either, or grep -rl "^## ADDED Requirements" openspec/specs/*/spec.md. archive then aborts and changes nothing.
  • openspec update takes no --no-animation (init does, update doesn't).
  • openspec init --tools hermes also refreshes tools already configured in that project (Claude Code, GitHub Copilot, OpenCode, .agents) to the new version, and leaves other tools' pre-existing skills alone.
  • Legacy ~/.codex/prompts/opsx-*.md are reported as deferred cleanup and are only deleted with openspec update --force once replacement skills exist.
  • A non-git project root means no project-local skill discovery in Hermes — check git rev-parse --show-toplevel when project skills seem missing.
  • external_dirs takes effect in the NEXT session; hermes skills list is the live check (it resolves openspec-* fine in a project whose cwd holds a copy).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.