SpecScribe 0.1.11-preview.12

This is a prerelease version of SpecScribe.
dotnet tool install --global SpecScribe --version 0.1.11-preview.12
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local SpecScribe --version 0.1.11-preview.12
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=SpecScribe&version=0.1.11-preview.12&prerelease
                    
nuke :add-package SpecScribe --version 0.1.11-preview.12
                    

SpecScribe

Build status for the main branch Coverage, measured by SonarQube Cloud

SpecScribe turns spec-driven-development artifacts into a human-readable website.

Frameworks like BMad (including its GDS game-development submodule) produce a wealth of markdown artifacts — PRDs, GDDs, epics, stories, requirements inventories, and architecture decision records. Those files are written for AI agents and power users, not for humans skimming project status. SpecScribe watches those artifacts and renders them into a styled, navigable, cross-linked static HTML site: epic and story dashboards with progress gauges, requirements traceability pages, rendered mermaid diagrams, and ADR indexes — regenerated live on every save.

Supported frameworks

SpecScribe renders artifacts from the spec-driven-development frameworks below. Support for additional frameworks is planned — see the Roadmap for feature-level plans.

Framework Version Status
BMad Method 6.10.0 ✅ Supported
BMad GDS (Game Dev Studio) 0.6.0 ✅ Supported
GitHub Spec Kit 🧭 Planned
GSD 1.42.3 ✅ Supported
GSD-Pi 🧭 Planned
Superpowers 🧭 Planned

GSD Core support is per artifact family, not blanket: phases and plans become epics and stories, milestones render as banded groups on the epics index, and .planning/STATE.md supplies the sprint view. Requirements, planning docs and commands are deliberately not projected — each for its own stated reason, spelled out on the portal's own About SDD › GSD page rather than left as unexplained blanks.

GSD and GSD-Pi are distinct products, not two versions of one thing. GSD Core is a slash-command framework layered on your AI coding runtime; it keeps every artifact as plain Markdown and JSON under .planning/, with no database, and decomposes work as Milestone → Phase → Task. GSD Pi is an autonomous agent CLI whose single source of truth is a SQLite database at .gsd/gsd.db; the Markdown beside it is rendered from that database, and work decomposes as Milestone → Slice → Task. The older gsd-build/gsd-2 repository is retired and continues as GSD Pi. SpecScribe reads Markdown only — never the database.

BMad modules

BMad is not one thing — it installs as a set of modules under _bmad/{code}/, and BMad Builder can mint new ones with arbitrary codes. SpecScribe identifies the installed module(s) from that directory name and tells you honestly how deeply it understands each one. Installing a second module never degrades the one you already had; a repo running BMM alongside Test Architect keeps its full BMM surface.

Module Code What SpecScribe does
BMad Method bmm Full projection — epics, stories, requirements, sprint, retros, planning docs, next-step commands, and the BMM glossary
Game Dev Studio gds Full projection — the same families, with GDD / narrative planning docs and GDS commands
Test Architect tea Named, with its test artifacts interpreted — they get their own page and a dashboard Module Coverage panel carrying the quality-gate verdict and coverage figures (see below)
Creative Intelligence Suite cis Named — its real label and its parsed command catalog; its markdown renders through the generic document pass
BMad Builder bmb Named — as above
Anything BMad Builder mints any Named — module identity is open-world, so a custom module is named rather than misidentified

"Named" is a deliberate, stated boundary rather than a gap. For every module below the top two — Test Architect included — SpecScribe publishes no glossary and no planning-doc set, and the dashboard's artifact-coverage panel is omitted rather than reporting eight BMad Method artifact families the module never produces. The run records that omission as a non-fatal note on the Diagnostics page, which also names the module actually detected.

Two BMad core skills — present in every install regardless of module — get first-class surfaces:

  • bmad-forge-idea → an Ideas page listing every forged idea workspace grouped by outcome (hardened / in progress / killed), each with a detail page, the original forge-report.html carried through verbatim, and forward links to the brief, PRD, or epic an idea produced where that link is evidenced on disk.
  • bmad-testarch-* (Test Architect) → a Test Artifacts page, plus the first non-markdown sources SpecScribe reads: gate-decision.json and e2e-trace-summary.json are read by exact filename so the PASS/CONCERNS/FAIL/WAIVED gate verdict is visible instead of silently invisible to the *.md scan.

Every discovered module artifact carries one of three coverage tiers, so the interpretation boundary is stated rather than guessed at:

Tier Meaning
Rendered The document has its own page; SpecScribe reads its prose but interprets none of its structure
Summarized SpecScribe extracts a structured headline — verdict, coverage figures — and surfaces it alongside the artifact, while the file itself is not fully modelled
Unsupported Discovered and named, nothing interpreted. Not an error — an honest statement of the boundary

Optional surfaces are omitted entirely when their artifacts don't exist: no forge workspaces means no Ideas page and no nav entry; no Test Architect artifacts means no Test Artifacts page and no Module Coverage panel.

Install

SpecScribe is a .NET global tool targeting .NET 10.

Not published to a package feed yet. Every Epic 16 release story is still backlog, so there is no nuget.org package and no tagged release. Install from a clone, and pin by commit SHA.

Prerequisites

  • .NET 10 SDK.
  • Node ^22.19.0 || ^24.11.0 || >=26.0.0 — needed at generate time, not just to build. SpecScribe renders every page through a prebuilt JavaScript renderer (ADR 0022), so generate boots Node and fails with an actionable message when it is missing or out of range.

Build the renderer, then install the CLI

Both halves are required. Since ADR 0034 no C# code path writes content HTML: generate emits the JSON IR, then boots the renderer artefact and requests one route per manifest entry. Without the artefact it produces an IR with no pages and exits non-zero.

# 1. Build the renderer artefact. Needs Node; the ~200 MB toolchain is build-time only
#    and is never shipped — what it produces is a ~2.2 MB pure-JS artefact.
cd web
SPECSCRIBE_PACKAGE_BUILD=1 npm ci   # PowerShell: $env:SPECSCRIBE_PACKAGE_BUILD='1'; npm ci
npm run sync:assets
npm run build:package               # MUST be build:package, never build — see below
cd ..

# 2. Pack and install the CLI.
dotnet pack src/SpecScribe -c Release -o artifacts
dotnet tool install --global SpecScribe --add-source ./artifacts

SPECSCRIBE_PACKAGE_BUILD=1 is what lets step 1 run on a fresh clone: postinstall: nuxt prepare loads web/nuxt.config.ts, which hard-fails when no IR is on disk, and on a fresh checkout there is none. The flag stubs the route manifest empty, which is exactly what it exists for.

Use build:package, never build. A plain nuxt build bakes this project's pages into .output/public, and Nitro serves public/ ahead of the SSR route — so an artefact built that way returns SpecScribe's own pages for your project, with HTTP 200. A wrong answer with a success status.

That puts specscribe on your PATH (%USERPROFILE%\.dotnet\tools), so you can run it from any project directory. To pick up a newer build later just re-pack and dotnet tool update --global SpecScribe --add-source ./artifacts — there is no version to bump by hand. The version comes from the nearest reachable git tag via MinVer, so an untagged working build is 0.1.0-preview.0.<commits-since> and a build on a v0.1.0-preview.1 tag is exactly 0.1.0-preview.1 (ADR 0040 § 5). Read the version off the produced .nupkg filename rather than typing one from memory.

Running against a project other than this one? That works with no extra configuration: the package carries its own renderer at tools/<tfm>/any/renderer/, which lands beside the executable in the tool store and is what generate resolves. SPECSCRIBE_RENDERER_DIR remains available as an explicit override — point it at a directory containing server/index.mjs and SpecScribe uses that one or stops, never a different one.

See docs/Packaging.md for how a package is produced and verified, and for the two ways a packaging change can produce a green build that ships a package which cannot render.

Usage

specscribe                  # interactive menu (generate / watch / configure paths)
specscribe generate         # generate the site once and exit
specscribe watch            # generate, then regenerate on every file save (Ctrl+C to stop)
specscribe --help           # full CLI help

Run with no arguments (or with unrecognized arguments) and SpecScribe drops into an interactive menu where you can generate, watch, or adjust paths before running.

Options

Both generate and watch accept:

Option Default
--source <DIR> Walks up from the current directory to find _bmad-output/
--adrs <DIR> <repo root>/docs/adrs
--output <DIR> <repo root>/SpecScribeOutput
--project-name <NAME> project_name from _bmad/config.toml, else "BMad Live Docs"
--deep-git Off — opt-in deeper git analytics (file hotspots + change coupling) as a distinct dashboard panel; leaving it off keeps baseline generation unaffected

With no options, SpecScribe auto-discovers a BMad project from wherever you run it — so inside a BMad repo, plain specscribe generate just works.

Publishing to GitHub Pages

You can publish SpecScribe output for any repository, not just this one.

What this costs today, stated up front. There is no published SpecScribe package, and the CLI cannot render without its Node renderer, so an external project must check SpecScribe out and build both halves. That is six steps whose order is load-bearing. Making this a single versioned step is Story 16.9 (backlog); until it ships, the workflow below is the supported path. It was verified end-to-end on 2026-08-06 against a separate repository — 940 pages, errors=0.

Create .github/workflows/publish-specscribe-pages.yml:

name: Publish SpecScribe Docs

on:
  push:
    branches: ["main"]
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: pages
  cancel-in-progress: false

env:
  # Pin SpecScribe by commit SHA: there is no tagged release yet, and the CLI and its
  # renderer MUST come from the same revision. Nothing validates a mismatched pair, and
  # the failure mode is wrong output rather than an error.
  SPECSCRIBE_REF: "<commit-sha>"

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - name: Check out your project
        uses: actions/checkout@v4
        with:
          # Full history so git metrics (commit count, activity heatmap) and the
          # opt-in deep analytics (--deep-git) reflect real history, not just the tip.
          fetch-depth: 0

      - name: Check out SpecScribe
        uses: actions/checkout@v4
        with:
          repository: IntegerMan/SpecScribe
          ref: ${{ env.SPECSCRIBE_REF }}
          path: .specscribe-src
          # REQUIRED. MinVer derives the version from tag reachability, and a shallow
          # clone has no tags — which yields a WRONG VERSION rather than an error.
          fetch-depth: 0

      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "10.0.x"

      - name: Setup Node
        # Version comes from SpecScribe's own pin, never a hand-typed number.
        uses: actions/setup-node@v4
        with:
          node-version-file: .specscribe-src/web/.nvmrc
          cache: npm
          cache-dependency-path: .specscribe-src/web/package-lock.json

      # ── The renderer must exist BEFORE the generate. ──────────────────────────────────
      # No C# path writes content HTML (ADR 0034). `generate` emits the IR, then boots this
      # artefact and requests one route per manifest entry. With no artefact every route
      # fails, errors=1, and the job exits non-zero having rendered nothing.
      - name: Build the SpecScribe renderer
        working-directory: .specscribe-src/web
        env:
          # `postinstall: nuxt prepare` loads nuxt.config.ts, which hard-fails when no IR is
          # on disk — and none is, this early. This flag stubs the manifest empty, which is
          # precisely what it exists for, and breaks the install-needs-IR cycle.
          SPECSCRIBE_PACKAGE_BUILD: "1"
        # `build:package`, NEVER `build`. A plain `nuxt build` bakes the building project's
        # pages into .output/public, and Nitro serves public/ ahead of the SSR route — so
        # the artefact would return SpecScribe's own pages for your project, at HTTP 200.
        run: npm ci && npm run sync:assets && npm run build:package

      - name: Install the SpecScribe CLI
        # --tool-path (not --global) keeps the install explicit and off PATH-guessing.
        # The version is derived from the git tag by MinVer, so there is no literal to
        # keep in step with the csproj — read it off the .nupkg the pack just produced.
        # (A hard-coded --version would break on the next commit, since an untagged
        # build carries a commit-height suffix.)
        run: |
          dotnet pack .specscribe-src/src/SpecScribe/SpecScribe.csproj -c Release -o sspkg
          VERSION=$(ls sspkg/SpecScribe.*.nupkg | sed 's|.*/SpecScribe\.||; s|\.nupkg$||')
          dotnet tool install SpecScribe --version "$VERSION" \
            --tool-path sstools --add-source sspkg

      - name: Generate the portal
        # No SPECSCRIBE_RENDERER_DIR: the package carries its own renderer beside the
        # executable, so an external project needs no pointer back into this checkout.
        # Runs from your repo root, so git analysis targets your history. Exits non-zero
        # if any page errors, so a broken portal fails the job instead of publishing.
        run: |
          ./sstools/specscribe generate \
            --source _bmad-output \
            --adrs docs/adrs \
            --output SpecScribeOutput \
            --project-name "My Project" \
            --deep-git

      - name: Upload pages artifact
        uses: actions/upload-pages-artifact@v4
        with:
          path: SpecScribeOutput

  deploy:
    needs: build
    runs-on: ubuntu-latest
    timeout-minutes: 10
    permissions:
      # Declared per job, not workflow-wide, so the build job above never carries
      # write scopes it does not need.
      contents: read
      pages: write
      id-token: write
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url || steps.deployment_retry.outputs.page_url }}
    steps:
      # GitHub's Pages backend intermittently returns "Deployment failed, try
      # again later." The first attempt may fail without failing the job; the
      # guarded retry re-invokes the deploy only when that happens.
      - id: deployment
        continue-on-error: true
        uses: actions/deploy-pages@v5

      - if: steps.deployment.outcome == 'failure'
        run: sleep 30

      - id: deployment_retry
        if: steps.deployment.outcome == 'failure'
        uses: actions/deploy-pages@v5

Notes:

  • Replace SPECSCRIBE_REF, the paths, and the project name for your layout.
  • Your project needs artifacts SpecScribe can read — today that means BMad (bmm/gds). Spec Kit, GSD and GSD-Pi are planned; see Supported frameworks.
  • Do not reorder the steps. The renderer build must precede the generate. This repository's own publish workflow regressed exactly that way once, and the reason it was missed is instructive: it had no Node steps at all, so nothing in it looked like it depended on the renderer.
  • generate exits non-zero when any page errors, so the job fails rather than publishing a broken portal. A missing or out-of-range Node fails with a message naming the supported range.
  • The deploy step is retried once because GitHub's Pages backend occasionally reports a transient Deployment failed, try again later. error; the retry avoids a full rebuild.
  • Full repository example workflow: https://github.com/IntegerMan/SpecScribe/blob/main/.github/workflows/publish-docs-live-pages.yml

Option B: Commit generated output and publish from that folder

If you commit generated site files, you can keep output in a single top-level folder like SpecScribeOutput and configure GitHub Pages to serve that published content from version control.

For this mode:

  • Run SpecScribe with --output SpecScribeOutput.
  • Commit and push the generated SpecScribeOutput files.
  • Configure GitHub Pages in repository settings to publish from the branch/folder setup that serves that directory.

This is useful if you prefer static output tracked in git instead of artifact-based deployment.

What it renders

  • Dashboard — project-wide progress, epic/story completion gauges, git activity stats
  • Epics & stories — parsed from BMad epics.md structure, grouped and cross-linked, with status pills
  • Requirements traceability — FR/NFR inventory with epic coverage maps; requirement IDs in any document become anchor links
  • ADRs — hand-authored architecture decision records rendered with rewritten cross-links
  • Ideas — forged idea workspaces grouped by outcome, with the original forge report and forward links to whatever the idea became (omitted when no ideas exist)
  • Test artifacts — Test Architect output with its quality-gate verdict, coverage figures, and a per-artifact coverage tier, plus a Module Coverage panel on the dashboard (omitted when absent)
  • Mermaid diagrams — fenced ```mermaid blocks render client-side
  • Task lists — GitHub-style checkboxes render as progress

Source files are always read with shared access; the watcher never holds a write lock on anything it observes.

Roadmap

Planned framework support (Spec Kit, GSD-Pi, Superpowers) is tracked in the Supported frameworks table above. Feature-level plans:

  • Git insights — richer history-derived views (velocity, file heatmaps) beyond the current commit stats
  • Directory-structure insights — project-layout overviews generated from the tree itself

Development

dotnet build            # build everything
dotnet test             # run the unit tests
dotnet run --project src/SpecScribe -- generate    # run without installing
pwsh tools/coverage/Get-Coverage.ps1               # browsable coverage report (add -Open to launch it)

The solution is SpecScribe.slnx; the tool lives in src/SpecScribe, tests in tests/SpecScribe.Tests.

The coverage report is written to the gitignored artifacts/coverage/html/. It renders the OpenCover file dotnet test already produces — it is not a second coverage mechanism — and it covers C# only, so its percentage is deliberately not the same number as the SonarCloud figure, which uses a different formula and also counts extension/ and web/. tools/coverage/README.md explains the difference and shows which figures to compare.

Continuous integration

Every push to main and every pull request builds the solution and runs the full test suite via .github/workflows/build-test-analyze.yml, which also submits the build to SonarQube Cloud for code-quality analysis.

Build and test need no configuration. The analysis half requires a one-time SonarCloud setup — generating a token and storing it as the SONAR_TOKEN repository secret — described in SonarCloud Setup. Until that is done CI still runs green; the scanner steps simply skip, which is also what happens on pull requests from forks, since GitHub does not share secrets with them.

Project health
Measure Value What it means
Build Passing The latest main run of build-test-analyze.yml built the solution and the full test suite went green.
Coverage 89.9% SonarQube Cloud's blended figure — covered lines and covered conditions over all lines and conditions to cover. This is the number the badge above shows.
Line coverage 91.9% Executable lines hit by the tests. Higher than the blended figure.
Branch coverage 85.7% Conditional branches taken by the tests. Lower than the blended figure.
Maintainability A — best rating No technical-debt band is dragging the rating down.
Reliability D — third-worst of five 12 open bugs sit inside the analysis's new-code window, the worst of them rated critical.
Security C — middle of five 164 open vulnerabilities sit inside the new-code window; 160 of them are one rule, csharpsquid:S6444 (regular expressions declared without a timeout).
Quality gate Failing — no badge shown The Sonar way gate reports ERROR, because it demands the best rating on both reliability and security for new code. See the paragraph below.

Measured 2026-07-29 against SonarQube Cloud's analysis of 240afae. These figures are a hand-written snapshot and go stale as soon as CI runs again — the two badges under the title are always live, this table is not. Refresh it with:

curl -s "https://sonarcloud.io/api/measures/component?component=IntegerMan_SpecScribe&metricKeys=alert_status,coverage,line_coverage,branch_coverage,sqale_rating,reliability_rating,security_rating"

Why there is no quality-gate badge. The gate is SonarQube Cloud's built-in Sonar way, and every one of its conditions is advisory here: the workflow deliberately leaves sonar.qualitygate.wait unset, so a failing gate never fails the build. The gate currently reports failing, and it will keep reporting failing until two sizeable cleanups land, because Sonar's A rating means zero open issues of that class rather than no severe ones. A permanently-red badge on the front page is worse than no badge, so the build and coverage badges ship on their own. SonarCloud Setup records what the gate asserts, what is holding it red, and who owns each cleanup.

License

MIT — Copyright (c) 2026 Matt Eland

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
0.1.11-preview.12 145 8/11/2026
0.1.10-preview.11 58 8/11/2026
0.1.9-preview.10 65 8/10/2026
0.1.6-preview.7 70 8/9/2026
0.1.5-preview.6 65 8/9/2026
0.1.3-preview.4 74 8/9/2026
0.1.1-preview.2 66 8/8/2026