Install the "openspec-aware-chorus" agent skill from https://github.com/Chorus-AIDLC/Chorus/tree/main/packages/chorus-dsh/skills/openspec-aware-chorus into .claude/skills/openspec-aware-chorus/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "openspec-aware-chorus", then confirm the skill loads.
Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Type this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
skills CLI
$ npx skills add Chorus-AIDLC/Chorus --skill openspec-aware-chorus -a codex
Project install goes to .agents/skills/; add -g for ~/.codex/skills/.
Install the "openspec-aware-chorus" agent skill from https://github.com/Chorus-AIDLC/Chorus/tree/main/packages/chorus-dsh/skills/openspec-aware-chorus into .agents/skills/openspec-aware-chorus/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "openspec-aware-chorus", then confirm the skill loads.
Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
skills CLI
$ npx skills add Chorus-AIDLC/Chorus --skill openspec-aware-chorus -a cursor
Project install goes to .agents/skills/; add -g for ~/.cursor/skills/.
Install the "openspec-aware-chorus" agent skill from https://github.com/Chorus-AIDLC/Chorus/tree/main/packages/chorus-dsh/skills/openspec-aware-chorus into .cursor/skills/openspec-aware-chorus/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "openspec-aware-chorus", then confirm the skill loads.
Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
skills CLI
$ npx skills add Chorus-AIDLC/Chorus --skill openspec-aware-chorus -a gemini-cli
Project install goes to .agents/skills/; add -g for ~/.gemini/skills/.
Install the "openspec-aware-chorus" agent skill from https://github.com/Chorus-AIDLC/Chorus/tree/main/packages/chorus-dsh/skills/openspec-aware-chorus into .gemini/skills/openspec-aware-chorus/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "openspec-aware-chorus", then confirm the skill loads.
Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Installs for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
skills CLI
$ npx skills add Chorus-AIDLC/Chorus --skill openspec-aware-chorus -a github-copilot
Project install goes to .agents/skills/; add -g for ~/.copilot/skills/.
Install the "openspec-aware-chorus" agent skill from https://github.com/Chorus-AIDLC/Chorus/tree/main/packages/chorus-dsh/skills/openspec-aware-chorus into .github/skills/openspec-aware-chorus/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "openspec-aware-chorus", then confirm the skill loads.
GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
skills CLI
$ npx skills add Chorus-AIDLC/Chorus --skill openspec-aware-chorus -a opencode
OpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
Install the "openspec-aware-chorus" agent skill from https://github.com/Chorus-AIDLC/Chorus/tree/main/packages/chorus-dsh/skills/openspec-aware-chorus into .opencode/skills/openspec-aware-chorus/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "openspec-aware-chorus", then confirm the skill loads.
OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Facts
Skill name
openspec-aware-chorus
GitHub stars
1.2k
Token cost
~7.5k tokens
SKILL.md length
3,106 words
Files
1
Skills in repo
64
Repo updated
First seen
Licence
AGPL-3.0
At a glance
OpenSpec-mode authoring for Chorus PM workflows on dsh — the default whenever OpenSpec is usable.
Works in 3 steps: CHORUS_OPENSPEC_MODE is not set to off… → The project root contains an openspec/… → The openspec CLI is on PATH.
Tasks that involve Computer vision
SKILL.md covers §1. Detection — read the mode…, §2. ⛔ Two non-negotiable rules, §3. OpenSpec mode authoring and §4. Fallback authoring…, plus 3 more sections
Calls npm, node and jq; needs CHORUS_API_KEY
What it does
Openspec Aware Chorus is an agent skill from Chorus-AIDLC/Chorus. OpenSpec-mode authoring for Chorus PM workflows on dsh — the default whenever OpenSpec is usable. Consumes the Spec Mode block the chorus-dsh bundle injects (mode resolved once at load by src/spec-mode.ts), scaffolds openspec/changes/<slug/ on disk, and mirrors Markdown files into Chorus document drafts via chorus mcp call --arg-file (package-local chorus-mcp-call.mjs wrapper as fallback). When OpenSpec isn't usable the mode resolves to spec-lite (see spec-lite-chorus). Required reading for the proposal, develop…
Its SKILL.md is about 7.5k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in AI & LLM Engineering, covering Computer vision, Project scaffolding and MCP servers. It works with Model Context Protocol. The repository describes itself as: The Agent Harness for AI-Human Collaboration, inspired by the AI-DLC (AI-Driven Development Lifecycle). The licence is AGPL-3.0.
When your agent uses it
Tasks that involve Computer vision
Tasks that involve Project scaffolding
Tasks that involve MCP servers
Example prompts
“/openspec-aware-chorus”
Requirements
Node.js
A credential in CHORUS_API_KEY
Workflow steps
3 steps, taken from the first numbered list in SKILL.md.
1CHORUS_OPENSPEC_MODE is not set to off (explicit opt-out wins).
2The project root contains an openspec/ directory (i.e. someone ran openspec init here).
3The openspec CLI is on PATH.
What it can do on your machine
Read from SKILL.md and the folder at commit 4754822. It shows what the files ask for, not the result of running them.
Tool permissions
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Runs code
Shell commands in SKILL.md call:
npm
node
jq
From the folder's file list and the shell code blocks in SKILL.md.
Network
Links to these hosts (documentation or services it may open):
github.com
From URLs in SKILL.md, links to its own repository left out.
Credentials
Names these keys or tokens, usually read from environment variables:
CHORUS_API_KEY
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Context cost
Openspec Aware Chorus loads about 7.5k tokens when it runs. Until then it costs about 143 tokens; SKILL.md has 3,106 words of instructions outside code blocks.
Always· name and description, kept in context so the agent knows when to use it
~143
When it runs· the whole SKILL.md, loaded when a task matches
~7.5k
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
Safety
Auto-check passed
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
Download SKILL.mdSave it as .claude/skills/openspec-aware-chorus/SKILL.md (or your agent's skills folder).
name
openspec-aware-chorus
description
OpenSpec-mode authoring for Chorus PM workflows on dsh — the default whenever OpenSpec is usable. Consumes the `## Spec Mode` block the chorus-dsh bundle injects (mode resolved once at load by `src/spec-mode.ts`), scaffolds `openspec/changes/<slug>/` on disk, and mirrors Markdown files into Chorus document drafts via `chorus mcp call --arg-file` (package-local `chorus-mcp-call.mjs` wrapper as fallback). When OpenSpec isn't usable the mode resolves to spec-lite (see `spec-lite-chorus`). Required reading for the proposal, develop, and yolo skills.
license
AGPL-3.0
metadata.author
chorus
metadata.version
0.22.0
metadata.category
project-management
metadata.mcp_server
chorus
OpenSpec-aware Authoring (dsh plugin)
This skill is a shared sub-procedure invoked by the Chorus stage skills (proposal, develop, yolo) whenever the resolved spec mode is a usable OpenSpec CLI setup. It is one of the modes the chorus-dsh bundle resolves at load:
Activates when the resolved spec mode is a usable OpenSpec (see §1): CHORUS_SPEC_MODE=openspecor unset, andCHORUS_OPENSPEC_MODE not off, an openspec/ directory at the project root, and the openspec CLI on PATH.
Otherwise the calling skill follows the resolved CHORUS_SPEC_MODE — spec-lite (the default when OpenSpec isn't usable) or free-form (=off). This skill is then a no-op.
See also — spec-lite-chorus (the lightweight fallback): OpenSpec (this skill) stays the default whenever it is usable. When OpenSpec is absent or disabled — or CHORUS_SPEC_MODE=lite — the mode resolves to spec-lite: a durable local .chorus/specs/<slug>/spec.md (never synced) + per-change dated folders <slug>/<YYYY-MM-DD>-<change-slug>/ of Chorus-typed docs mirrored 1:1 into Chorus via the same --arg-file transport. See the spec-lite-chorus skill.
Tool namespace: Chorus MCP tools are exposed under a mcp__chorus__ prefix on dsh (e.g. mcp__chorus__chorus_pm_create_proposal). Bare names are used in prose for readability — prepend mcp__chorus__ when invoking the MCP tools directly. Document-mirror calls do NOT go through the MCP harness at all — they go through the chorus CLI (chorus mcp call, preferred) or the package-local chorus-mcp-call.mjs wrapper (fallback) (see §2 Rule 1), which talk to the Chorus MCP endpoint over HTTP using your API key, independent of the mcp__chorus__ namespacing.
§1. Detection — read the mode the bundle already resolved
dsh difference: the Claude Code plugin resolves the spec mode in a SessionStart hook. dsh has no SessionStart hook, but the chorus-dsh bundle resolves the mode once at plugin load (resolveSpecMode, the single source of truth — the TS mirror of the canonical bash resolver) and both (a) injects a ## Spec Mode block into your first-step context and (b) publishes CHORUS_SPEC_MODE + CHORUS_OPENSPEC_ACTIVE to the process environment, before the daemon-origin gate, so interactive and daemon-woken sessions inherit it. Consume that value — do NOT re-run detection and do NOT hand-roll an OpenSpec-only check.
The bundle marks OpenSpec active (a CHORUS_OPENSPEC_ACTIVE=1 line + CHORUS_SPEC_MODE=openspec) only when CHORUS_SPEC_MODE is openspecor unset, and all three of these hold:
CHORUS_OPENSPEC_MODE is not set to off (explicit opt-out wins).
The project root contains an openspec/ directory (i.e. someone ran openspec init here).
The openspec CLI is on PATH.
Both signals (2) and (3) are required because the OpenSpec authoring path needs the working directory and the CLI — having one without the other leaves the workflow unrunnable. If signal (2) holds but (3) does not, the bundle's ## Spec Mode note carries an install hint (npm i -g @fission-ai/openspec); pass it through if asked rather than silently choosing another mode.
How to read the value
Look for the ## Spec Mode section near the top of your context:
or (resolved to lite / off — no CHORUS_OPENSPEC_ACTIVE=1 line):
## Spec Mode
CHORUS_SPEC_MODE=lite (default — OpenSpec not usable: no openspec/ directory at /path/to/repo/openspec)
Branch:
CHORUS_OPENSPEC_ACTIVE=1 line present (equivalently the CHORUS_OPENSPEC_ACTIVE env var is 1) → follow §3 (OpenSpec authoring).
No CHORUS_OPENSPEC_ACTIVE=1 → this skill is a no-op; return to the caller, which follows the resolved CHORUS_SPEC_MODE (spec-lite — see the spec-lite-chorus skill — or free-form when =off). Do not scaffold openspec/changes/. Do not add the slug line to the proposal description.
Manual fallback (context genuinely absent)
If you were spawned mid-session without the ## Spec Mode context, read the environment variables the bundle published — CHORUS_OPENSPEC_ACTIVE (1 ⇒ §3) and CHORUS_SPEC_MODE (lite/off ⇒ no-op, caller follows that mode). Never hand-roll an OpenSpec-only three-check that hard-codes "else free-form" — that ignores CHORUS_SPEC_MODE and mis-routes a lite repo to free-form. Only if both env vars are genuinely unset (a broken/older bundle) resolve the full mode yourself: an explicit CHORUS_SPEC_MODE (lite/openspec/off) wins; otherwise OpenSpec is active iff CHORUS_OPENSPEC_MODE ≠ offand an openspec/ dir is present andopenspec --version succeeds, else the mode is spec-lite (never free-form-by-default).
bash
# Last-resort resolution when NEITHER CHORUS_OPENSPEC_ACTIVE nor CHORUS_SPEC_MODE
# was published (broken bundle). PROJECT_DIR defaults to $PWD (dsh exports no CLAUDE_PROJECT_DIR).
PROJECT_DIR="${PWD}"
case "${CHORUS_SPEC_MODE:-}" in
openspec|"") : ;; # may be OpenSpec — probe below
lite|off) echo "no-op: follow CHORUS_SPEC_MODE=$CHORUS_SPEC_MODE"; return 0 2>/dev/null || exit 0 ;;
esac
if [ "${CHORUS_OPENSPEC_MODE:-}" != "off" ] && [ -d "${PROJECT_DIR}/openspec" ] && openspec --version >/dev/null 2>&1; then
RESOLVED_OPENSPEC_ACTIVE=1 # follow §3
else
RESOLVED_OPENSPEC_ACTIVE=0 # no-op; caller follows spec-lite (default), NOT free-form
fi
echo "RESOLVED_OPENSPEC_ACTIVE=$RESOLVED_OPENSPEC_ACTIVE"
§2. ⛔ Two non-negotiable rules
Both are enforced at review time. Both have caused incidents in past releases.
Rule 1 — Fill content from the file (CLI preferred, bash-wrapper fallback); never re-type document content from agent output
Document/draft mirror calls (chorus_pm_add_document_draft, chorus_pm_update_document_draft, chorus_pm_update_document) MUST fill the content field from the local file's bytes, never from a hand-typed body. Calling these tools directly from the agent's MCP harness with a hand-typed content field is a protocol violation for OpenSpec mode and will fail review. Use whichever transport is available, preferred first:
Primary — the chorus CLI:chorus mcp call <tool_name> '<json-without-content>' --arg-file content=<file>. --arg-file content=<path> reads the file's raw bytes and injects them as the JSON content string, byte-exact — the CLI's built-in replacement for json_encode_file, so no helper is needed. chorus mcp call reads the same CHORUS_URL / CHORUS_API_KEY from the dsh process environment. See §3.6. Requires chorus >= 0.17.0 (the chorus mcp subcommand was added then; an older CLI errors with "unknown command"); on any version or unknown-command failure, upgrade with npm install -g @chorus-aidlc/chorus.
Fallback — the package-local chorus-mcp-call.mjs wrapper ($CHORUS_MCP_CALL), when chorus is not on PATH: build $PAYLOAD with the json_encode_file helper and call "$CHORUS_MCP_CALL" <tool_name> "$PAYLOAD" (availability note below). Defined in the §3.6 fallback block.
New to the chorus CLI? See the chorus-cli skill for install, configuring agents (chorus agents add|remove|list), the connection env vars, and chorus mcp basics.
Acting identity — which agent the call acts as.chorus mcp call resolves the agent from, in order: CHORUS_AGENT_PROFILE (a name or UUID) → CHORUS_URL + CHORUS_API_KEY in the environment → the single agent configured in ~/.chorus/daemon.json. A daemon-woken session already has CHORUS_AGENT_PROFILE set. If a mirror call fails with Multiple agents … specify --agent (several agents configured and no profile/creds in the env), pass your own identity explicitly: chorus mcp call <tool> … --agent <your-agentUuid> — your UUID is in your chorus_checkin result, and chorus agents lists every configured name/UUID.
Reasons (they apply to both paths):
Token cost. Re-typing a multi-thousand-line markdown body through the LLM burns input + output tokens for every draft. Both the CLI's --arg-file and the fallback's json_encode_file (§3.6, Node JSON.stringify) stream the file's bytes into the JSON string — content never enters LLM context. A typical 3-doc proposal mirror costs roughly zero content-tokens this way; via direct MCP with a re-typed body it routinely costs 20k+.
Byte-equality. A file-fill path (CLI --arg-file, or the fallback's JSON.stringify of the file's UTF-8 bytes) is a byte-faithful encoder: backslashes, quotes, newlines, code-fence content, zero-width chars all survive. LLM re-emission has a non-zero failure rate on long markdown — table alignment drifts, fence escapes get "fixed", long URLs wrap. The byte-equality guarantee (modulo trailing \n) holds only on a file-fill path, never on LLM re-emission.
Single source of truth. With a file-fill mirror, the local openspec/changes/<slug>/*.md is authoritative and Chorus is a mirror. With agent re-typing, authority splits between local file and whatever the LLM happened to output — a future diff cannot tell which one is correct.
Wrapper availability on dsh (fallback path). When you fall back to the wrapper, the npm bundle publishes its path in CHORUS_MCP_CALL at plugin load. Validate it before authoring:
bash
if [ -z "${CHORUS_MCP_CALL:-}" ] || [ ! -x "$CHORUS_MCP_CALL" ]; then
echo "ERROR: OpenSpec mirroring requires the package-local CHORUS_MCP_CALL wrapper; reload the Chorus dsh bundle." >&2
exit 1
fi
The wrapper reads CHORUS_URL and CHORUS_API_KEY from the dsh process environment (so does chorus mcp call). If both chorus and the wrapper are missing, halt visibly. Do not reproduce it ad hoc and do not retype document content through the model.
Rule 2 — Halt on error via chorus_check_response
Every wrapper call must check three signals: wrapper exit code, "error": in body, empty body. Bare RC=$? is insufficient — the wrapper exits 0 on HTTP 401 (auth failure) with empty body, so a single-signal check silently misses the most common runtime failure. See §6 for the helper definition.
§3. OpenSpec mode authoring
3.1 Pick a slug
openspec/changes/<slug>/ is the local change folder. The slug must be:
kebab-case (add-export-csv, not addExportCsv or add_export_csv),
derived from the source Idea title,
unique within openspec/changes/.
Record it for later steps:
bash
SLUG="add-export-csv"
3.2 Scaffold the change folder
bash
openspec new change "$SLUG" --description "<one-line idea summary>"
This creates openspec/changes/$SLUG/ with README.md and .openspec.yaml. Then author by hand:
Local file
Purpose
Mirror as Document.type
proposal.md
Why + What Changes + Capabilities + Impact
prd
design.md
Architecture, contracts, risks
tech_design
specs/<capability>/spec.md
Delta spec (## ADDED Requirements + Scenarios)
spec (one draft per capability)
tasks.md
OpenSpec tasks list
(not mirrored — Chorus task drafts are source of truth)
Use openspec instructions <artifact> --change "$SLUG" (artifacts: proposal, specs, design, tasks) for templates.
3.3 Spec file shape (verified against openspec instructions specs)
A delta spec lists one or more block headers — ## ADDED Requirements, ## MODIFIED Requirements, ## REMOVED Requirements, ## RENAMED Requirements — and within each, ### Requirement: entries. Mix freely in the same file; only include the blocks you actually need.
## ADDED Requirements
Append a brand-new Requirement to the long-term spec.
## ADDED Requirements
### Requirement: <name>
<requirement text — use SHALL / MUST for normative behavior>
#### Scenario: <name>
- **WHEN** <condition>
- **THEN** <expected outcome>
## MODIFIED Requirements
Whole-block replacement, not merge. Whatever you write here completely replaces the existing same-named Requirement in the long-term spec — title, description, and all scenarios. Half-writing it deletes the rest.
Rename a Requirement's title. Body and scenarios are preserved as-is in the long-term spec; use MODIFIED instead if you need to change anything besides the title.
Scenarios MUST use exactly 4 hashtags (#### Scenario:). 3 hashtags or a bullet list silently fail validation.
Every ### Requirement: under ADDED or MODIFIED MUST have at least one #### Scenario:.
MODIFIED blocks MUST include the full updated content — they overwrite, not patch.
Use SHALL / MUST for normative requirements; avoid should / may.
The merge into openspec/specs/<capability>/spec.md happens at openspec archive time (§3.9), not at proposal time. While the proposal is in flight, Chorus only sees the delta file as one spec Document — there is no half-merged state for the skill to reason about.
Optional:
bash
openspec validate "$SLUG"
3.4 Filling the content field byte-exact
The document content must be inserted byte-for-byte from the local file — never re-typed by the LLM. Two mechanisms, preferred first:
Primary — chorus mcp call … --arg-file content=<path> (§3.6). The CLI reads the file's raw bytes and injects them as the JSON content string. This is the byte-faithful replacement for json_encode_file, so on the CLI path no helper is needed — pass the base JSON without a content field and let --arg-file fill it.
Fallback — json_encode_file (defined in the §3.6 fallback block, used only when chorus is not on PATH). It encodes the file into a byte-faithful JSON string with Node's JSON.stringify — Node is guaranteed present under dsh (it is the harness runtime), so no jq is required.
Round-trip: the Chorus backend appends a single \n to draft content on write, so server content is byte-equal modulo a trailing newline. Reviewers diffing local file vs server should ignore that one byte.
3.5 Create the proposal container with the slug provenance line
Use the regular chorus_pm_create_proposal MCP tool (no wrapper required for this single call — the description is short, the LLM-emitted version is fine). The description must carry exactly one line:
OpenSpec change slug: <slug>
on its own line (no other text on that line),
literal prefix OpenSpec change slug: (capital O, capital S, single space after colon),
no trailing punctuation,
value matches the slug passed to openspec new change.
This line is machine-grep-able by future runs of this skill and by the §3.9 archive trigger.
Show full SKILL.md (1,250 more words)Show less
3.6 Mirror each document draft (CLI primary, wrapper fallback)
Rule 1 reminder:content comes from the file's bytes, never a hand-typed body. The agent must not retype the document body.
Define the halt-on-error helper from §6 once at the top. Primary path — the chorus CLI: pass the base JSON without a content field and let --arg-file content=<file> fill it byte-exact. One call per file:
bash
# PRD draft — --arg-file fills content byte-exact from the file; no json_encode_file needed.
RESULT=$(chorus mcp call chorus_pm_add_document_draft \
"{\"proposalUuid\":\"$PROPOSAL_UUID\",\"type\":\"prd\",\"title\":\"PRD: $HUMAN_TITLE\"}" \
--arg-file content="openspec/changes/$SLUG/proposal.md")
RC=$?
chorus_check_response "chorus_pm_add_document_draft (prd)" "$RC" "$RESULT"
PRD_DRAFT_UUID=$(printf '%s' "$RESULT" | grep -o '"draftUuid"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
Repeat with type: "tech_design" for design.md, and one call per capability with type: "spec" for each specs/<capability>/spec.md. Do not mirror tasks.md — Chorus task drafts (created via the chorus_pm_add_task_draft MCP tool, no wrapper needed) are the source of truth for tasks.
Why parsing uses printf '%s' "$RESULT" | grep not echo "$RESULT" | jq: echo interprets backslash sequences inside the captured JSON, turning embedded \n into a real newline. jq then aborts with Invalid string: control characters from U+0000 through U+001F must be escaped. printf '%s' emits the captured bytes verbatim. Same pattern applies to all wrapper-result parsing in this skill.
Fallback — when the chorus CLI is not on PATH
If command -v chorus fails, mirror through the package-local chorus-mcp-call.mjs wrapper resolved into $CHORUS_MCP_CALL (Rule 1). Define json_encode_file here (it is used only on this fallback path), then build $PAYLOAD with an embedded content. The chorus_check_response halt-on-error check applies exactly as on the primary path.
bash
# Define once, fallback-only: byte-faithful file → JSON string via Node.
json_encode_file() {
# Byte-faithful: JSON.stringify of the file's UTF-8 content — quotes,
# backslashes, newlines, code-fence content, and control chars all survive.
# No jq, no curl.
node -e 'const fs=require("fs");process.stdout.write(JSON.stringify(fs.readFileSync(process.argv[1],"utf8")))' "$1"
}
# PRD draft
CONTENT=$(json_encode_file "openspec/changes/$SLUG/proposal.md")
PAYLOAD=$(cat <<JSON
{
"proposalUuid": "$PROPOSAL_UUID",
"type": "prd",
"title": "PRD: $HUMAN_TITLE",
"content": $CONTENT
}
JSON
)
RESULT=$("$CHORUS_MCP_CALL" chorus_pm_add_document_draft "$PAYLOAD")
RC=$?
chorus_check_response "chorus_pm_add_document_draft (prd)" "$RC" "$RESULT"
PRD_DRAFT_UUID=$(printf '%s' "$RESULT" | grep -o '"draftUuid"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
3.7 Editing a draft after the first mirror
Local file changes propagate via chorus_pm_update_document_draft — same primary/fallback split as §3.6, same halt check. Primary (CLI):
Once the proposal is approved, drafts materialize into Documents with their own UUIDs. To keep openspec/changes/$SLUG/ and the Chorus Document in sync, mirror file edits via chorus_pm_update_document. Primary (CLI):
To re-derive $SPEC_DOCUMENT_UUID from a fresh shell, look it up via chorus_get_documents for the proposal's project and match by title + type. Re-derive $SLUG by grepping the proposal's description for ^OpenSpec change slug: .
3.9 Archive after the last task is verified
dsh difference: the Claude Code plugin has a PostToolUse hook (bin/on-post-verify-task.sh) that fires after chorus_admin_verify_task and injects an openspec archive <slug> reminder. dsh has no such hook. You (the agent) must detect the trigger yourself: after each chorus_admin_verify_task, check whether the just-verified task was the LAST task of its OpenSpec-mode idea (every Task across every approved Proposal of that idea is now done/closed, and the proposal description carries an OpenSpec change slug: <slug> line). If so, run the archive flow below. If not, do nothing.
When the trigger holds, you perform the archive:
Run archive locally. Use --yes for non-interactive mode. Do NOT pass --skip-specs (defeats the mirror-back) or --no-validate (lets malformed deltas corrupt cumulative specs).
bash
openspec archive "$SLUG" --yes
This moves openspec/changes/$SLUG/ under openspec/changes/archive/<date>-<slug>/ and emits/updates openspec/specs/<capability>/spec.md for each capability. (Run openspec archive --help against your installed version to confirm the current flag set — flags can drift between releases.)
Mirror each updated openspec/specs/<capability>/spec.md back to the matching post-approval Chorus Document (§3.8 contract). chorus_get_documents only supports projectUuid + type server-side filters; filter by title client-side. One chorus_pm_update_document call per capability.
Halt on any error from openspec archive or chorus_pm_update_document. Print stderr verbatim, post a comment on the proposal recording the failure (chorus_add_comment with targetType: "proposal", targetUuid: <proposalUuid>), then stop. No retry. Matches §6 "no silent errors." (Comment on the proposal, not the idea: the failure is in archiving proposal-derived specs, and proposals can be inputType: "document" with no idea attached.)
Confirm success. List openspec/specs/<capability>/spec.md files and verify they round-trip byte-equal (modulo trailing newline) with their Chorus Document counterparts.
Strict opt-in: if the verified task is not the last of its idea, OR the proposal description carries no OpenSpec change slug: <slug> line, OR the local shell has no openspec CLI, do nothing — no archive. Existing free-form behavior is preserved.
§4. Fallback authoring (OpenSpec not active)
When §1 shows OpenSpec is not active (no CHORUS_OPENSPEC_ACTIVE=1), this skill is a no-op. Return to the calling skill, which follows the resolved CHORUS_SPEC_MODE — spec-lite (the default when OpenSpec isn't usable; see the spec-lite-chorus skill) or free-form (=off). From this skill's side, regardless of which:
No openspec/changes/ folder is created or referenced.
No OpenSpec change slug: … line is added to the proposal description.
The §3.9 archive flow does nothing (no slug → no archive).
The two downstream modes differ, and this skill does not own either:
spec-lite (CHORUS_SPEC_MODE=lite) → the caller loads spec-lite-chorus: a durable .chorus/specs/<slug>/spec.md (never mirrored) + dated per-change folders whose Chorus-typed docs are mirrored byte-exact via the same --arg-file transport + chorus_check_response helper as §3.6.
free-form (CHORUS_SPEC_MODE=off) → document drafts are authored via direct MCP chorus_pm_add_document_draft calls with inline content — same as before this skill existed; Rule 1 (file-fill mirror) does not apply since there is no local file source of truth.
prd, tech_design, spec are pre-existing valid Document.type values — no schema change required.
§6. Failure visibility — the chorus_check_response helper
This helper guards both the primary CLI path and the fallback wrapper path. The Node wrapper exits non-zero on transport failures, HTTP 4xx/5xx, and JSON-RPC error bodies (e.g. a 401 from a bad CHORUS_API_KEY exits 2, a tool-level error exits 4); chorus mcp call likewise exits non-zero on tool/transport errors. Still check all three signals below as defense in depth: a bare RC=$? is fine for the common cases but this helper also catches a well-formed 200 body that nonetheless carries an "error" object, and an unexpectedly empty body.
Define this helper once at the top of the authoring session and use it after every mirror call (CLI or wrapper):
bash
chorus_check_response() {
local _tool="$1"
local _rc="$2"
local _body="$3"
local _has_error=0
local _is_empty=0
local _trimmed
_trimmed=$(printf '%s' "$_body" | tr -d ' \t\n\r')
[ -z "$_trimmed" ] && _is_empty=1
if [ "$_is_empty" -eq 0 ]; then
# No jq required: a substring match on an "error" key is sufficient for the
# mirror tools, whose success bodies carry no top-level "error" field.
printf '%s' "$_body" | grep -qE '"error"[[:space:]]*:' && _has_error=1
fi
if [ "$_rc" -ne 0 ] || [ "$_has_error" -eq 1 ] || [ "$_is_empty" -eq 1 ]; then
echo "ERROR: $_tool failed (exit=$_rc, error_in_body=$_has_error, empty_body=$_is_empty)" >&2
echo "Output: $_body" >&2
[ "$_rc" -ne 0 ] && exit "$_rc" || exit 1
fi
}
Anti-patterns — do not:
Collapse to || true.
Redirect stderr to /dev/null.
Bury the wrapper call inside a pipeline (masks $?).
Skip capturing $RESULT into a variable; the helper needs the body.
Use only if [ "$RC" -ne 0 ]; then ... — that misses the HTTP-error path.
Minimal call site shape (both paths):
bash
# Primary — chorus CLI:
RESULT=$(chorus mcp call <tool_name> '<json-without-content>' --arg-file content=<file>)
RC=$?
chorus_check_response "<tool_name>" "$RC" "$RESULT"
# Fallback — chorus-mcp-call.mjs via $CHORUS_MCP_CALL (chorus not on PATH):
RESULT=$("$CHORUS_MCP_CALL" <tool_name> "$PAYLOAD")
RC=$?
chorus_check_response "<tool_name>" "$RC" "$RESULT"
# ...if we reach here, the call succeeded; parse RESULT and continue.
This is project-wide policy: no silent errors.
§7. Quick reference checklist
When invoked from a stage skill (proposal / develop / yolo):
Read the mode the chorus-dsh bundle already resolved (§1) — the ## Spec Mode context, or the CHORUS_OPENSPEC_ACTIVE / CHORUS_SPEC_MODE env vars. Do NOT re-run detection or hand-roll an OpenSpec-only check. If that context is genuinely absent, use the §1 manual fallback.
If there's no CHORUS_OPENSPEC_ACTIVE=1 → no-op; return to the caller, which follows the resolved CHORUS_SPEC_MODE (spec-lite via spec-lite-chorus, or free-form when =off) — see §4.
Otherwise:
a. Pick $SLUG (§3.1).
b. openspec new change "$SLUG" (§3.2).
c. Author proposal.md, design.md, specs/<capability>/spec.md (§3.2–§3.3). Mix ADDED / MODIFIED / REMOVED / RENAMED blocks as needed; remember MODIFIED overwrites the whole Requirement.
d. Optional: openspec validate "$SLUG".
e. chorus_pm_create_proposal (direct MCP) with the OpenSpec change slug: $SLUG line in description (§3.5).
f. Define the chorus_check_response helper. Prefer chorus mcp call … --arg-file content=<file> for mirrors (§3.6) — no json_encode_file needed on that path; validate the executable path in $CHORUS_MCP_CALL and define json_encode_file only when falling back to the wrapper because chorus is not on PATH.
g. For each row in §5 with "yes" — mirror via chorus mcp call chorus_pm_add_document_draft … --arg-file content=<file> (§3.6; fallback = "$CHORUS_MCP_CALL" chorus_pm_add_document_draft). Record each $DRAFT_UUID.
h. On any failed chorus_check_response — halt, surface the error, do NOT proceed.
Edits before approval → §3.7. Edits after approval → §3.8.
Last task verified → detect the trigger yourself (no hook) → run §3.9 archive flow.
Openspec Aware Chorus next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
Openspec Aware Chorus compared with similar skills
Skill
Stars
Used in
Tokens
Auto-check
Licence
Repo updated
Openspec Aware Chorus this skillChorus-AIDLC/Chorus
Calls an external vision model through vision.js to analyze an image when the user explicitly invokes /skill luma-vision, for agents whose own model cannot see images.
Generates AI-BOM, MCP inventory, AI skill inventory, and AI authorship provenance documents with cdxgen, cataloging models, inference services, Hugging Face purls, MCP servers and their…
Routes general Lunora requests to the right Lunora skill and gives the shared mental model (codegen loop, generated api/internal references, review commands, add-on capabilities, the @lunora/mcp…
A skill your agent uses when manually verifying a Chorus frontend change in a real browser — finding local login credentials, driving the running dev server with the Playwright MCP, logging in…
OpenSpec-mode authoring for Chorus PM workflows on dsh — the default whenever OpenSpec is usable. Openspec Aware Chorus is an agent skill from Chorus-AIDLC/Chorus. OpenSpec-mode authoring for Chorus PM workflows on dsh — the default whenever OpenSpec is usable.
When should I use Openspec Aware Chorus?
Openspec Aware Chorus fits situations like: tasks that involve Computer vision; tasks that involve Project scaffolding; tasks that involve MCP servers.
How do I install Openspec Aware Chorus in Claude Code?
Run `npx skills add Chorus-AIDLC/Chorus --skill openspec-aware-chorus -a claude-code`. Or copy the skill folder (packages/chorus-dsh/skills/openspec-aware-chorus in Chorus-AIDLC/Chorus) into .claude/skills/openspec-aware-chorus in your project. Claude Code loads it when a task matches its description.
How do I install Openspec Aware Chorus in Codex?
Run `npx skills add Chorus-AIDLC/Chorus --skill openspec-aware-chorus -a codex`. Or copy the skill folder (packages/chorus-dsh/skills/openspec-aware-chorus in Chorus-AIDLC/Chorus) into .agents/skills/openspec-aware-chorus in your project. Codex loads it when a task matches its description.
Can I use Openspec Aware Chorus in Cursor, Gemini CLI or GitHub Copilot?
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add Chorus-AIDLC/Chorus --skill openspec-aware-chorus -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/openspec-aware-chorus, .gemini/skills/openspec-aware-chorus, .github/skills/openspec-aware-chorus and .opencode/skills/openspec-aware-chorus in your project.
What does Openspec Aware Chorus need to run?
Going by SKILL.md and its folder, Openspec Aware Chorus needs the command-line tools its instructions call (npm, node and jq) and credentials named CHORUS_API_KEY. Our summary lists: Node.js; A credential in CHORUS_API_KEY.
Does Openspec Aware Chorus access the network?
SKILL.md names 1 domain. As links in the text: github.com. This is read from the text; nothing was executed.
Is Openspec Aware Chorus safe to install?
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
What licence does Openspec Aware Chorus use?
Openspec Aware Chorus is published under the AGPL-3.0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
How many tokens does Openspec Aware Chorus use?
About 7.5k tokens (SKILL.md is roughly 30k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
What are the alternatives to Openspec Aware Chorus?
Skills that share tags, products or a category with Openspec Aware Chorus: Chatgpt Apps (Haohao-end/openagent, 808 stars), Luma Vision Image Analysis (JochenYang/luma-mcp, 116 stars), Pi Agent (K-Dense-AI/scientific-agent-skills, 48k stars) and MCP Scaffold (timothywarner-org/claude-code, 224 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
Who maintains Openspec Aware Chorus?
Chorus-AIDLC (a GitHub organization) maintains it in Chorus-AIDLC/Chorus, which has 1,191 GitHub stars. The repository holds 64 skills in this directory. The repository was last updated on October 9, 2026.
Source: Chorus-AIDLC/Chorus on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.