From ca0c163c3b5f8e31a0b992d1f364b7c2652a0754 Mon Sep 17 00:00:00 2001 From: NguyenDuong Date: Mon, 23 Mar 2026 08:08:37 +0700 Subject: [PATCH 1/2] Add SessionStart and PreToolUse hooks for SpecForge workflow enforcement SessionStart hook (pattern from obra/superpowers): - Injects plugin context at every session start so Claude always knows available commands, skills, agents, and key workflow rules PreToolUse Write|Edit hook: - Blocks direct edits to Approved spec files (O, UC, S, BR, ACT, WF, ST, PM, DT, NFR, INT prefixes with Status: Approved) - Returns actionable deny message directing user to /phase-delta or /change-request instead Co-Authored-By: Claude Sonnet 4.6 --- hooks/context.md | 41 +++++++++++++++++++++++++++ hooks/hooks.json | 31 +++++++++++++++++++- hooks/scripts/guard-approved-specs.sh | 38 +++++++++++++++++++++++++ hooks/scripts/session-start.sh | 26 +++++++++++++++++ 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 hooks/context.md create mode 100755 hooks/scripts/guard-approved-specs.sh create mode 100755 hooks/scripts/session-start.sh diff --git a/hooks/context.md b/hooks/context.md new file mode 100644 index 0000000..fa77b8c --- /dev/null +++ b/hooks/context.md @@ -0,0 +1,41 @@ +You have the SpecForge plugin loaded. SpecForge is a spec-driven development toolkit that turns requirements into sprint-ready work following IEEE 830 / ISO 29148 standards. + +## Available Slash Commands + +| Command | Usage | Purpose | +|---|---|---| +| `/new-spec` | `/new-spec ` | Create a spec from template (object, usecase, screen, businessrule, actor, workflow, nfr, etc.) | +| `/new-epic` | `/new-epic ` | Generate an epic from a use case | +| `/new-story` | `/new-story ` | Create a user story with spec traceability | +| `/new-sprint` | `/new-sprint ` | Create a sprint plan from ready stories | +| `/meeting-note` | `/meeting-note ` | Capture meeting notes with UR extraction | +| `/check-traceability` | `/check-traceability [scope]` | Scan for orphans and coverage gaps | +| `/phase-delta` | `/phase-delta ` | Create a Phase 2+ delta for an approved spec | +| `/change-request` | `/change-request ` | Log a formal change request | +| `/impact-analysis` | `/impact-analysis <CR code>` | Run blast-radius analysis on a CR | +| `/apply-change` | `/apply-change <CR code>` | Execute an approved change request | + +## Auto-Triggering Skills + +These activate automatically based on what you are doing — you do not need to invoke them manually: + +- **spec-writer** — activates when writing or editing any specification document +- **requirement-decomposer** — activates when decomposing specs into epics, stories, or sprints +- **traceability-checker** — activates when verifying cross-references or coverage + +## Available Agents + +Invoke these for complex multi-step tasks: + +- **spec-reviewer** — IEEE 830 / ISO 29148 quality review with scored report +- **decomposition-agent** — auto-decompose a use case into an epic + user stories +- **traceability-agent** — build or validate the full Requirements Traceability Matrix +- **change-impact-agent** — autonomous blast-radius analysis for a change request + +## Key Rules (Always Follow) + +1. **Never edit Approved specs directly** — always use `/phase-delta <spec code>` to create a Phase 2 delta. Every change must trace to a CR code. +2. **Naming conventions** — O<NN>_, UC<NNNN>_, S<NNNN>_, BR<NNNN>_, ACT<NNNN>_, WF<NNNN>_, ST<NNNN>_, PM<NNNN>_, NFR<NNNN>_, EPIC-NNNN_, US-NNNN_, SPR-NNNN_ +3. **Spec output directory** — write all generated spec artifacts to `docs/` +4. **Templates** — always copy from `templates/` when creating new specs; never create from scratch +5. **Traceability** — every user story must trace back to at least one SRS artifact (UC, Object, Screen, BR, etc.) diff --git a/hooks/hooks.json b/hooks/hooks.json index 0967ef4..4d7379c 100644 --- a/hooks/hooks.json +++ b/hooks/hooks.json @@ -1 +1,30 @@ -{} +{ + "description": "SpecForge BA workflow hooks: injects plugin context at session start and guards approved specs from direct edits.", + "hooks": { + "SessionStart": [ + { + "matcher": "startup|clear|compact", + "hooks": [ + { + "type": "command", + "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/session-start.sh\"", + "async": false, + "timeout": 10 + } + ] + } + ], + "PreToolUse": [ + { + "matcher": "Write|Edit", + "hooks": [ + { + "type": "command", + "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/guard-approved-specs.sh\"", + "timeout": 10 + } + ] + } + ] + } +} diff --git a/hooks/scripts/guard-approved-specs.sh b/hooks/scripts/guard-approved-specs.sh new file mode 100755 index 0000000..afb36c2 --- /dev/null +++ b/hooks/scripts/guard-approved-specs.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# SpecForge PreToolUse hook — Write|Edit +# Blocks direct edits to Approved spec files. +# Rule: Approved specs must never be edited directly — create a Phase 2 delta instead. +# See: CLAUDE.md "Phase 2 Delta Pattern" and /phase-delta command. + +set -euo pipefail + +input=$(cat) + +# Extract the file path from the tool input +file_path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty' 2>/dev/null) + +if [ -z "$file_path" ]; then + exit 0 +fi + +# Only check files that look like SpecForge spec artifacts +# Matches: O01_, UC0001_, S0001_, BR0001_, INT0001_, NFR0001_, +# ACT0001_, WF0001_, ST0001_, PM0001_, DT0001_ +basename=$(basename "$file_path") +if ! [[ "$basename" =~ ^(O[0-9]{2}|UC[0-9]{4}|S[0-9]{4}|BR[0-9]{4}|INT[0-9]{4}|NFR[0-9]{4}|ACT[0-9]{4}|WF[0-9]{4}|ST[0-9]{4}|PM[0-9]{4}|DT[0-9]{4})_ ]]; then + exit 0 +fi + +# Only check files that actually exist (new files are always allowed) +if [ ! -f "$file_path" ]; then + exit 0 +fi + +# Check if the spec has Status: Approved +if grep -qiE "^\*?\*?Status\*?\*?\s*[:|]\s*Approved" "$file_path" 2>/dev/null; then + spec_code=$(printf '%s' "$basename" | grep -oE '^[A-Z]+[0-9]+' || echo "$basename") + printf '%s' "{\"decision\":\"deny\",\"reason\":\"Direct edit blocked: ${spec_code} has Status: Approved. Per SpecForge change management rules, approved specs must never be edited directly. Run /phase-delta ${spec_code} to create a Phase 2 delta, or /change-request to log a formal CR first.\"}" + exit 2 +fi + +exit 0 diff --git a/hooks/scripts/session-start.sh b/hooks/scripts/session-start.sh new file mode 100755 index 0000000..a6de8c5 --- /dev/null +++ b/hooks/scripts/session-start.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# SpecForge SessionStart hook +# Injects SpecForge plugin context into every new Claude Code session so that +# Claude is always aware of available commands, agents, skills, and key rules. +# Pattern adapted from obra/superpowers session-start hook. + +set -euo pipefail + +PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/../.." && pwd)}" +CONTEXT_FILE="${PLUGIN_ROOT}/hooks/context.md" + +if [ ! -f "$CONTEXT_FILE" ]; then + exit 0 +fi + +# Read and JSON-escape the context content (no subshells, pure bash) +content=$(<"$CONTEXT_FILE") +content="${content//\\/\\\\}" +content="${content//\"/\\\"}" +content="${content//$'\n'/\\n}" +content="${content//$'\r'/}" +content="${content//$'\t'/\\t}" + +payload="{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"${content}\"}}" + +printf '%s' "$payload" From fd5c2d45a3ba4d8375d99f876cf8de265b92a718 Mon Sep 17 00:00:00 2001 From: NguyenDuong <nguyenduonghaui94@gmail.com> Date: Mon, 23 Mar 2026 08:11:51 +0700 Subject: [PATCH 2/2] Remove approved spec guard hook Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --- hooks/hooks.json | 14 +--------- hooks/scripts/guard-approved-specs.sh | 38 --------------------------- 2 files changed, 1 insertion(+), 51 deletions(-) delete mode 100755 hooks/scripts/guard-approved-specs.sh diff --git a/hooks/hooks.json b/hooks/hooks.json index 4d7379c..6c63155 100644 --- a/hooks/hooks.json +++ b/hooks/hooks.json @@ -1,5 +1,5 @@ { - "description": "SpecForge BA workflow hooks: injects plugin context at session start and guards approved specs from direct edits.", + "description": "SpecForge BA workflow hooks: injects plugin context at session start.", "hooks": { "SessionStart": [ { @@ -13,18 +13,6 @@ } ] } - ], - "PreToolUse": [ - { - "matcher": "Write|Edit", - "hooks": [ - { - "type": "command", - "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/guard-approved-specs.sh\"", - "timeout": 10 - } - ] - } ] } } diff --git a/hooks/scripts/guard-approved-specs.sh b/hooks/scripts/guard-approved-specs.sh deleted file mode 100755 index afb36c2..0000000 --- a/hooks/scripts/guard-approved-specs.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -# SpecForge PreToolUse hook — Write|Edit -# Blocks direct edits to Approved spec files. -# Rule: Approved specs must never be edited directly — create a Phase 2 delta instead. -# See: CLAUDE.md "Phase 2 Delta Pattern" and /phase-delta command. - -set -euo pipefail - -input=$(cat) - -# Extract the file path from the tool input -file_path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty' 2>/dev/null) - -if [ -z "$file_path" ]; then - exit 0 -fi - -# Only check files that look like SpecForge spec artifacts -# Matches: O01_, UC0001_, S0001_, BR0001_, INT0001_, NFR0001_, -# ACT0001_, WF0001_, ST0001_, PM0001_, DT0001_ -basename=$(basename "$file_path") -if ! [[ "$basename" =~ ^(O[0-9]{2}|UC[0-9]{4}|S[0-9]{4}|BR[0-9]{4}|INT[0-9]{4}|NFR[0-9]{4}|ACT[0-9]{4}|WF[0-9]{4}|ST[0-9]{4}|PM[0-9]{4}|DT[0-9]{4})_ ]]; then - exit 0 -fi - -# Only check files that actually exist (new files are always allowed) -if [ ! -f "$file_path" ]; then - exit 0 -fi - -# Check if the spec has Status: Approved -if grep -qiE "^\*?\*?Status\*?\*?\s*[:|]\s*Approved" "$file_path" 2>/dev/null; then - spec_code=$(printf '%s' "$basename" | grep -oE '^[A-Z]+[0-9]+' || echo "$basename") - printf '%s' "{\"decision\":\"deny\",\"reason\":\"Direct edit blocked: ${spec_code} has Status: Approved. Per SpecForge change management rules, approved specs must never be edited directly. Run /phase-delta ${spec_code} to create a Phase 2 delta, or /change-request to log a formal CR first.\"}" - exit 2 -fi - -exit 0