openspec-aware
The openspec-aware skill enables opt-in spec-driven authoring for Chorus project management workflows when the OpenSpec CLI and project structure are present. It detects activation signals at session start, scaffolds change directories on disk, and syncs Markdown drafts to Chorus documents, serving as a shared sub-procedure for proposal, develop, and yolo stage skills.
git clone --depth 1 https://github.com/Chorus-AIDLC/Chorus /tmp/openspec-aware && cp -r /tmp/openspec-aware/public/chorus-plugin/skills/openspec-aware ~/.claude/skills/openspec-awareSKILL.md
# OpenSpec-aware Authoring (Claude Code plugin)
This skill is a **shared sub-procedure** invoked by the Chorus stage skills (proposal, develop, yolo) whenever the user wants spec-driven authoring through the [OpenSpec CLI](https://github.com/Fission-AI/OpenSpec). It is opt-in:
- Activates when **all three** signals hold (see §1): `CHORUS_OPENSPEC_MODE` is not `off`, an `openspec/` directory exists at the project root, and the `openspec` CLI is on `PATH`.
- Otherwise the calling skill falls back to its existing free-form behavior.
When you reach a point in proposal / develop / yolo where this skill is referenced, **read the value of `CHORUS_OPENSPEC_ACTIVE` from the SessionStart context** (see §1) and branch on it. Do not re-run the detection block — the SessionStart hook has already done it once for this session.
---
## §1. Detection — already done at SessionStart
The Chorus plugin's SessionStart hook (`bin/on-session-start.sh`) computes `CHORUS_OPENSPEC_ACTIVE` once when the session opens and writes a `## OpenSpec Mode` section into the plugin's injected context. The value of `CHORUS_OPENSPEC_ACTIVE` is `1` only when **all three** of these hold:
1. `CHORUS_OPENSPEC_MODE` is **not** set to `off` (explicit opt-out wins).
2. The project root contains an `openspec/` directory (i.e. someone ran `openspec init` here).
3. 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 SessionStart hook surfaces a "OpenSpec repo detected — install with: `npm i -g @fission-ai/openspec`" hint to the user; the agent should pass this through if asked rather than silently choosing free-form.
### How to read the value
You should already see something like this in your context (look for the `## OpenSpec Mode` section near the top of the conversation):
```
## OpenSpec Mode
CHORUS_OPENSPEC_ACTIVE=1 (openspec/ directory + openspec CLI both present)
```
or:
```
## OpenSpec Mode
CHORUS_OPENSPEC_ACTIVE=0 (no openspec/ directory at /path/to/repo/openspec)
```
Branch:
- `CHORUS_OPENSPEC_ACTIVE=1` → follow §3 (OpenSpec authoring).
- `CHORUS_OPENSPEC_ACTIVE=0` → return to the calling skill's free-form path. **Do not** scaffold `openspec/changes/`. **Do not** add the slug line to the proposal description.
### Manual fallback
If you're in a sub-shell, sub-agent, or session that did not see SessionStart context (e.g. you were spawned mid-session and the parent's context was not forwarded), reconstruct the value yourself with the same three checks:
```bash
if [ "${CHORUS_OPENSPEC_MODE:-}" = "off" ]; then
CHORUS_OPENSPEC_ACTIVE=0
elif [ ! -d "${CLAUDE_PROJECT_DIR:-$PWD}/openspec" ]; then
CHORUS_OPENSPEC_ACTIVE=0
elif ! openspec --version >/dev/null 2>&1; then
CHORUS_OPENSPEC_ACTIVE=0
else
CHORUS_OPENSPEC_ACTIVE=1
fi
```
Use this only when SessionStart context is genuinely unavailable — duplicating the detection is wasteful when the hook already computed it.
---
## §2. ⛔ Two non-negotiable rules
Both are enforced at review time. Both have caused incidents in past releases.
### Rule 1 — Mirror via the wrapper, 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** go through:
```
chorus-api.sh mcp-tool <tool_name> "$PAYLOAD"
```
`chorus-api.sh` is on `PATH` — call it by name.
with `$PAYLOAD` built using `json_encode_file` (defined in §3.4). 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. Reasons:
1. **Token cost.** Re-typing a multi-thousand-line markdown body through the LLM burns input + output tokens for every draft. The wrapper streams bytes through `jq -Rs '.'` — content never enters LLM context. A typical 3-doc proposal mirror via the script costs roughly zero content-tokens; via direct MCP it routinely costs 20k+.
2. **Byte-equality.** `jq -Rs '.'` 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 the wrapper path.
3. **Single source of truth.** With the wrapper, 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.
### 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 perImplement tasks from an OpenSpec change (Experimental)
Archive a completed change in the experimental workflow
Enter explore mode - think through ideas, investigate problems, clarify requirements
Propose a new change - create it and generate all artifacts in one step
Write release blog posts for Chorus — problem-first narrative, bilingual (zh/en), following the project's editorial style.
Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.
Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.
Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.