name: mxSpec description: Use when the user says "/spec", "/mxSpec", "write a spec", "write a specification", "requirements doc", "acceptance criteria", "define requirements", or needs to specify a feature or component before planning or implementation. Creates or updates specifications via MCP-Tools in the mxLore knowledge DB; tracks acceptance criteria with auto-archive on full completion. allowed-tools: Read, Write, Edit, Grep, Glob
Output Format ⚡
FIRST line of every response = ### REPORT ### EXACTLY. Position 0. Nothing before.
Read ~/.claude/skills/_shared/reasoning-leak-rule.md.
/mxSpec — Create/Update Specification (AI-Steno: !=forbidden →=use ⚡=critical ?=ask)
Spec-Agent. Creates/updates specifications in Knowledge-DB via MCP.
Verification ⚡
!invent structural facts. Verify via Grep/Read/mx_search BEFORE writing — 6 targets:
- Class names | Method/function names | File paths | i18n namespaces | AC/test counts | Plan/ADR/doc IDs
Verification fails -> drop the claim, or tag inline **unverified:** <reason>. See references/verification-examples.md for per-target Grep/Glob commands and rationale.
Init
- CLAUDE.md→
**Slug:**=project-param. ∅slug→?user - mx_ping()→OK=MCP-mode | Error=Local(
docs/specs/SPEC-<slug>.md+Warning→/mxMigrateToDb)
Input
Slug from command argument. ∅arg→?user.
⚡ Slug normalization:
- Lowercase, replace
[^a-z0-9-]with-, collapse + strip outer-. Then truncate to 100 chars at a-boundary, strip trailing-. Verify^[a-z0-9-]+$. - If normalized slug differs from input → show both and confirm with user.
Workflow
0) PRD Context
- Full brainstorming in session → derive PRD from chat, no follow-up questions.
- Otherwise (partial / no brainstorming, PRD-gaps): if the
superpowersplugin is installed, delegate tosuperpowers:brainstorming, then return here; if not, derive the PRD inline — ask the user the missing purpose / constraint / success-criteria questions one at a time. - Updating existing spec → skip Phase 0 entirely.
0b) Supersedes-FR Body-Load ⚡
When input lists supersedes: / consolidates: / merges: (case-insensitive):
- Parse the supersedes-list (
FR#NNNN,[FR-NNNN],Spec#NNNN,[SPEC-slug]). mx_detail(doc_id, max_content_tokens=1500)for each merged doc body.- Embed
## Konsens (aus supersedeten FRs)section in the new spec — one bullet per merged doc with Goal/target extract. - Conflicts → explicit
## Decisionblock (fires Section 3b auto-suggest) OR## Open Questionsentry. Never silently pick one body's answer. - In Section 2, add
mx_add_relation(..., relation_type='supersedes')per merged FR (alongsidereferencesedges). - Out-of-scope: Section 3 Update path (supersedes is CREATE-time-only).
1) Check existence
⚡ mx_search(project, doc_type='spec', query='<slug>', status='active', include_content=false, limit=5) — MUST pass status='active' or an archived spec with the same slug will hijack the Update path and mutate historical records.
For each result, verify the slug field matches the normalized input EXACTLY (mx_search uses full-text, so foo can match foo-v2). Only an exact-slug active hit goes to Update (step 3) with that doc_id; ∅exact match → New (step 2).
2) New Spec
Template → ~/.claude/skills/mxSpec/assets/spec-template.md (9 sections: Overview, Related, Goals, Non-goals, Requirements, Acceptance Criteria, Interfaces/Data, Edge Cases, Open Questions — plus title/meta lines). ⚡ Absolute path — the subagent CWD is the project root, not the skill dir, so a relative assets/… read silently fails. If the template file is unreadable, fall back to a minimal inline skeleton (Overview + Requirements + Acceptance Criteria) and warn the user.
⚡ Title clamp: server ClampTitle=255. Keep titles short.
MCP: mx_create_doc(project, doc_type='spec', title='SPEC: <Title>', content) — ⚡ Slug is auto-generated server-side from the title; the slug= param does not exist on mx_create_doc and is silently ignored. Server handles dedup via ClampSlug + retry-with-suffix (see references/bug-history.md).
Related handling (iterate, do not stop at first):
- Parse the Related section for ALL referenced ADRs + plans. Canonical bracket form:
[ADR-NNNN],[PLAN-slug]. Reject ambiguous formats likeADR#123— warn and skip. - For each →
mx_search(project, doc_type='decision,plan', query='<id-or-slug>', status='active', limit=3)to resolve target_id. - For each resolved target →
mx_add_relation(source_doc_id=<new spec doc_id>, target_doc_id=<target doc_id>, relation_type='references'). ⚡ source = new spec, target = ADR/plan; never reverse. Server dedupes. - Loop until all Related items processed.
Local (Fallback): ensure docs/specs/ exists (mkdir -p docs/specs); if index.md is absent create it with a minimal header, otherwise APPEND the new entry to the existing index (never overwrite). Write docs/specs/SPEC-<slug>.md + warning. ⚡ This fallback violates the ADR-0004 "local docs/ = only CLAUDE.md+status.md" rule — only used when MCP is unavailable; re-sync via /mxMigrateToDb once MCP is back.
3) Update Spec
MCP: mx_detail(doc_id, max_content_tokens=0) → modify only the target section(s) → update Last Modified to today in UTC (YYYY-MM-DD) → mx_update_doc(doc_id, content, change_reason).
⚡ max_content_tokens=0 is REQUIRED for updates — the 600-token default is for queries; using it on edits silently truncates and round-trips data loss.
⚡ Preserve all headers and existing sections; edit in place. Editing rules:
- Add a requirement / AC: append a new numbered line under
## Requirementsor a new- [ ]under## Acceptance Criteria; do NOT replace the whole section. - Complete an AC: flip
- [ ]to- [x](or- [X]); do NOT remove the line. - Remove an obsolete AC: annotate as
- [x] ~~original text~~ (dropped)rather than deleting the line. The strike-through preserves audit history. ⚡ Dropped AC do NOT count towardMorN— they are excluded from the status-transition totals (see step 4). Do NOT delete AC lines silently. - Resolve an Open Question: prepend
[resolved](case-insensitive —[Resolved],[RESOLVED],[done],[DONE]all accepted) and the resolution text; keep the original line. The status-transition check matches any of these prefixes as resolved.
⚡ Server clamp limits: title=255, slug=100, change_reason=500. Long values past the limit are silently truncated. See references/bug-history.md.
Local: Read → Edit → "Last Modified" to today → index update if status changed.
3b) Decision-Marker Detection + Auto-Suggest /mxDecision
After body-validation passes BUT BEFORE the final mx_create_doc/mx_update_doc call, scan the spec body for inline Decision-Markers that should live as separate ADRs.
Read ~/.claude/skills/_shared/decision-marker.md for the canonical regex + fence-exclusion algorithm.
If len(markers) == 0 → skip prompt, proceed to mx_create_doc/mx_update_doc.
If len(markers) > 0 → emit ONE batched prompt at end of Create/Update event (not per-marker spam):
Detected N decision-marker(s) in spec body. Persist as separate /mxDecision (ADR)? (y / n / skip-once / show)
Branches:
- y → invoke
/mxDecisionvia Skill-Tool with pre-filled args: marker-line + 2 lines context above + 2 lines below +parent_spec=<spec_id>. /mxDecision returnsdecision_id. THEN:mx_add_relation(source_doc_id=spec_id, target_doc_id=decision_id, relation_type='references')— BROAD-SKIP idempotency: skip if ANY source→target relation exists between this spec_id and decision_id, regardless of relation_type (handles user-manualsupersedes/implementslinks without creating duplicate edge).mx_remove_tags(spec_id, ['unbacked-decision'])if tag present (stale-tag closure). Idempotent — re-run on already-untagged spec is no-op. On failure: log warning, continue.
/mxDecision-abort: skip relation+tag-clear, leave spec untouched
- n →
mx_add_tags(spec_id, ['unbacked-decision']). Idempotent — re-run on already-tagged spec → no duplicate. - skip-once → no tag, no relation, no prompt. Event-scoped only — next Create/Update re-evaluates from scratch.
- show → display all detected markers with line numbers, then re-prompt with same 4 choices.
Multiple markers → list all in single batched prompt with line refs, accept user's single-choice answer for the batch.
4) Status Transition (on update)
AC counting: Count - [ ] / - [x] lines under ## Acceptance Criteria. Skip fenced code blocks. Exclude ~~text~~ (dropped) lines. M = total live, N = checked. If M == 0: skip transition (output Spec has no acceptance criteria yet). Status whitelist: only active auto-transitions.
- Open Questions: unresolved if line does NOT match case-insensitive
^\s*\[(resolved|done)\]. - M > 0 AND N == M AND no unresolved Open Questions AND status ==
active→ add**Status:** implemented, callmx_update_doc(doc_id, content, status='archived', change_reason='All AC fulfilled'), outputSpec #<doc_id> archived — all Acceptance Criteria fulfilled. ⚡ If any AC is(dropped), warnAuto-archive skipped — spec has <K> dropped AC. Confirm intent before archiving.and only archive after user confirmation. - Mixed (N < M): info only
<N>/<M> AC fulfilled. No change. - Open Questions unresolved: no archive even if AC complete. Note
AC complete but open questions remain. - ⚡ Doubt → leave open + ?user.
Rules
- ⚡ Only verified knowledge from chat !invent. ∅info→?user or Open Question
- ⚡ Related: mx_search verify BEFORE mx_add_relation
- !invented metrics in AC. !implementation details→/mxPlan
- Requirements numbered. AC clearly testable !vague
- MCP preferred, local=fallback
Completion
Output (max 20 lines, truncate aggressively):
- doc_id
- Top 3-5 Acceptance Criteria (truncate each to 60 chars)
- Up to 3 relations if created (show target title + doc_id only)
- Recommendations:
/mxDesignCheckerfor a spec review pass (catches gaps + inconsistencies before implementation)/mxDecisionif an ADR is needed for an architectural choice surfaced by the spec/mxPlan <slug>to derive an implementation plan from the spec
- If active workflow → name next step
If more AC or relations exist than shown, append ... and N more (see mx_detail <doc_id>).