npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@faviovazquez/sprang

v0.2.4

Published

Knowledge graph dashboard for any codebase — scan, visualize, and chat about your code.

Readme


Sprang is a knowledge graph platform for Windsurf (Cascade / Devin Desktop), Claude Code, and GitHub Copilot that creates total comprehension of codebases, knowledge bases, and document vaults — not just symbol search, but why code exists, who changed it, what it risks, and how it all fits together.

Your AI agent is the intelligence layer. Sprang is the memory. Together they answer "what will break if I change this file?" in a single tool call — and "how does this codebase actually work?" for anyone who just joined the team.

"The System knows everything about being, but nothing about existence."
Kierkegaard's critique of Hegel applies equally to symbol indexers and grep tools.
Sprang bridges the gap: from static facts to living, contextual understanding.


The Leap

Det qualitative Spring — the qualitative leap — is Kierkegaard's name for a discontinuous jump in understanding: the kind that cannot be reached by incremental steps, no matter how many you take.

Symbol search finds where things are. Documentation says what they were meant to do. An LLM can explain individual files brilliantly — and still lose the plot at file 50, forget the conversation from yesterday, and have no way to answer the question that matters most: what breaks if I change this, before I break it?

These answers require different infrastructure — one that understands the codebase before your agent starts working, persists that understanding across sessions, and makes the hard questions answerable in a single tool call:

  • Why does this file exist?sprang_why reads git history, PR references, and team annotations
  • What breaks if I change it?sprang_diff_impact runs BFS over the full dependency graph
  • How risky is it?sprang_health surfaces blast radius × coupling × test gap × churn, scored 0–1
  • What does this codebase actually do?/sprang-onboard gives a persona-adaptive guided tour

The leap becomes repeatable. The graph persists. The context accumulates.


Not just codebases

The same infrastructure works for knowledge bases: Obsidian vaults, Logseq databases, Dendron workspaces, Foam wikis, Zettelkasten archives, or any folder of markdown. Notes become nodes. Links become edges. Topic clusters emerge. The same Ask Agent panel, the same force-directed graph, the same guided reading order — just pointed at your notes instead of your code.

/sprang-knowledge /path/to/your/obsidian-vault

Installation

Note: Windsurf AI and Devin Desktop are the same product — Windsurf was rebranded as Devin Desktop. All instructions, skills, and workflows are identical for both. Both names appear in this README.

Quick install (npm) — the easiest path for every platform

Two commands set up any project for any agent — no clone, no build, no manual file copying:

npm install -g @faviovazquez/sprang
cd my-project
sprang init --platform claude     # or: copilot | windsurf | all

sprang init --platform <agent> does everything in one step:

  • writes the MCP config where your agent reads it — .mcp.json (Claude Code), .vscode/mcp.json (Copilot), or .devin/config.json (Windsurf/Devin) — with the absolute path to the bundled MCP server already filled in;
  • copies that agent's slash commands, rules, workflows, skills, and merge.py into the project.

Then build the graph and open the dashboard:

sprang scan            # build the knowledge graph (Phase 1, ~15 s)
sprang open            # launch the dashboard at http://localhost:7777

The package is published under the scoped name @faviovazquez/sprang, but the command it installs is just sprang. Run sprang init with no --platform to write only .mcp.json (no slash commands).

The sprang npm package bundles the dashboard, MCP server, CLI, and every platform's agent-integration files into a single tarball — no separate build step, no pnpm workspace, no Node version pinning beyond Node 22.

npm install -g vs npx? Every command also runs without installing — npx @faviovazquez/sprang scan, npx @faviovazquez/sprang open, etc. But prefer the global install for sprang init: it writes the bundled MCP server's absolute path into your project's .mcp.json, and a global install keeps that path stable, whereas the npx cache path can be pruned by npm and silently break your MCP config. Global install also gives you the short sprang … command everywhere.


Platform comparison

| Feature | Claude Code | Windsurf / Devin Desktop | GitHub Copilot | |---|---|---|---| | 9 MCP tools | ✅ .mcp.json (project) | ✅ global or per-project | ✅ Agent mode only | | 11 slash commands | ✅ .claude/commands/ | ✅ workflows + skills | ⚡ via skills | | Always-on rules | ✅ .claude/rules/ | ✅ .devin/ + .windsurf/rules/ | ⚡ copilot-instructions.md | | Auto-loaded instructions | CLAUDE.md | AGENTS.md | AGENTS.md + copilot-instructions.md | | Session hooks | ✅ stale graph warn + auto-refresh | — | — | | Dashboard Ask Agent | ✅ claude -p with --resume | ✅ via cascade-messaging extension | ✅ copilot --prompt CLI | | Conversation continuity | ✅ session ID in .sprang/claude-session.json | ✅ via agent-conversation.md | ✅ session ID in .sprang/copilot-session.json |

Recommended: Claude Code or Windsurf/Devin Desktop for the fullest experience. GitHub Copilot works with MCP tools in Agent mode but does not have session hooks.


Claude Code

Via the plugin marketplace (recommended)

Run these two commands inside a Claude Code session:

/plugin marketplace add FavioVazquez/sprang
/plugin install sprang

The first command registers the GitHub repo as a local marketplace source (reads .claude-plugin/marketplace.json). The second installs the plugin. Then build the MCP server binary to unlock all 9 tools:

# Find and build in the plugin cache (the exact version path may differ)
cd "$(ls -d ~/.claude/plugins/cache/sprang/sprang/*/ | tail -1)"
pnpm install && pnpm build

Then run /reload-plugins inside Claude Code to activate the MCP server.

Note on skill names: Plugin skills are namespaced by plugin name. After installation, commands are invoked as /sprang:sprang, /sprang:sprang-onboard, /sprang:sprang-analyze, etc. If you want the shorter unnamespaced form (/sprang, /sprang-onboard), copy the standalone files into your project (see the manual install below).

What the plugin activates:

| Component | What it does | |---|---| | skills/ | 11 slash commands (namespaced: /sprang:sprang, /sprang:sprang-onboard, …) | | hooks/hooks.json | Session start warns on stale graph; post-commit incremental refresh | | .mcp.json (via plugin.json) | 9 MCP tools — started automatically using ${CLAUDE_PLUGIN_ROOT} path | | CLAUDE.md | Claude Code project instructions — read automatically on every session open |

Or manually copy into your project (gives unnamespaced /sprang, /sprang-onboard commands):

SPRANG_DIR=~/.sprang/repo   # wherever install.sh cloned to, or your local clone
cp "$SPRANG_DIR/.mcp.json" .
cp "$SPRANG_DIR/CLAUDE.md" .
cp "$SPRANG_DIR/AGENTS.md" .
cp -r "$SPRANG_DIR/.claude" .
cp -r "$SPRANG_DIR/skills" .   # merge.py for /sprang-analyze (the plugin install bundles this automatically)

Then update .mcp.jsonargs to point to the absolute server path: "$SPRANG_DIR/packages/mcp/dist/server.js".

/sprang-analyze needs skills/sprang-analyze/scripts/merge.py to assemble the final graph. The plugin install bundles it; for a manual copy, the cp -r "$SPRANG_DIR/skills" . line above brings it in. Without it the analyze run can't write a valid knowledge-graph.json.

What Claude does automatically (once rules are active):

  • Before editing any file — calls sprang_node to check risk_score and structural_warnings
  • On high-risk files (risk > 0.7) — calls sprang_why to read decision context and team annotations before changing anything
  • After every change — calls sprang_diff_impact with changed files to assess blast radius
  • On session open — warns if the graph is missing or stale vs. current git HEAD
  • After git commits — silently triggers an incremental Phase 1 graph refresh in the background

To build the knowledge graph after install:

/sprang:sprang           # via plugin (namespaced)
/sprang                  # via manual copy (unnamespaced)
/sprang:sprang-onboard   # guided architecture tour (via plugin)

GitHub Copilot

Via gh skill install (recommended, requires GitHub CLI 2.90.0+)

gh skill install FavioVazquez/sprang

This installs Sprang's skills into ~/.copilot/skills/, making them available across all your Copilot sessions. Then build the MCP server to enable the 9 tools:

# Clone (or update) and build — only needed once
git clone https://github.com/FavioVazquez/sprang.git ~/.sprang/repo
cd ~/.sprang/repo && pnpm install && pnpm build

Copy .vscode/mcp.json into your project and update the path, then open VS Code with Copilot in Agent mode:

mkdir -p .vscode
cp ~/.sprang/repo/.vscode/mcp.json .vscode/mcp.json
# Edit .vscode/mcp.json → set the absolute path to ~/.sprang/repo/packages/mcp/dist/server.js

Or clone manually (without gh skill):

git clone https://github.com/FavioVazquez/sprang.git ~/.sprang/repo
cd ~/.sprang/repo && pnpm install && pnpm build

Open VS Code with Copilot, switch to Agent mode (the model selector in the chat panel), and .vscode/mcp.json auto-connects the MCP server when placed in your project root.

What activates:

| File | What it does | |---|---| | ~/.copilot/skills/sprang*/ | Skills installed globally — Copilot loads them in all sessions | | .vscode/mcp.json | MCP server — auto-connects in Agent mode (place in your project root) | | .github/copilot-instructions.md | Pre-edit checklist: check risk score before editing, blast radius after — auto-loaded by Copilot in every session | | AGENTS.md | Universal cross-platform instructions — both Windsurf/Devin Desktop and GitHub Copilot read this automatically |

MCP tools only work in Copilot Agent mode — not the default ask/edit modes.

What Copilot does automatically:

  • Every session — reads AGENTS.md and .github/copilot-instructions.md; the pre-edit checklist reminds it to call sprang_node before editing and sprang_diff_impact after
  • In Agent mode — 9 MCP tools available directly; Copilot can call sprang_health, sprang_why, sprang_diff_impact, etc. without being asked

Dashboard Ask Agent — the Sprang dashboard auto-detects the copilot CLI and can route questions through it non-interactively. Uses --resume=<session_id> for conversation continuity. Session stored in .sprang/copilot-session.json.

Copilot has a shallower integration than Claude Code or Windsurf — no session hooks that fire automatically, and MCP tools require Agent mode. The pre-edit instructions still meaningfully change how Copilot approaches edits in a Sprang-enabled project.


Windsurf / Devin Desktop — agentic install

Paste this prompt into Cascade or Devin. It handles everything: clones, builds, wires up the MCP server, copies slash commands, skills, and rules, runs the first scan, and starts the dashboard.

Please install the Sprang knowledge graph platform for this project.
Run all steps sequentially using terminal commands. Do not ask me for input between steps.

1. Clone Sprang to ~/tools/sprang, or pull latest if it already exists:
   if [ -d ~/tools/sprang ]; then
     git -C ~/tools/sprang pull --ff-only
   else
     git clone https://github.com/FavioVazquez/sprang.git ~/tools/sprang
   fi

2. Install dependencies and build all packages (run both in ~/tools/sprang):
   pnpm install
   pnpm build

3. Install the CLI globally so `sprang` works from any terminal:
   npm install -g @faviovazquez/sprang
   Verify: sprang --version  (should print 0.2.4 or later)

4. Copy rules, workflows, skills, and hooks into the current project:

   Rules — tell Cascade/Devin to use Sprang automatically:
     mkdir -p .devin/rules .windsurf/rules
     cp ~/tools/sprang/.devin/rules/sprang-context.md .devin/rules/
     cp ~/tools/sprang/.devin/rules/sprang-highrisk.md .devin/rules/
     cp ~/tools/sprang/.devin/rules/cascade-messaging.md .devin/rules/
     cp ~/tools/sprang/.windsurf/rules/sprang-context.md .windsurf/rules/
     cp ~/tools/sprang/.windsurf/rules/sprang-highrisk.md .windsurf/rules/
     cp ~/tools/sprang/.windsurf/rules/cascade-messaging.md .windsurf/rules/

   Hooks — enable persistent dashboard chat (conversation history):
     mkdir -p .devin .windsurf/hooks
     cp ~/tools/sprang/.devin/hooks.json .devin/hooks.json
     cp ~/tools/sprang/.windsurf/hooks/save-conversation.py .windsurf/hooks/save-conversation.py

   Devin Desktop MCP config — write .devin/config.json using the ACTUAL resolved path to
   ~/tools/sprang (do NOT copy the repo template — it has a relative path that won't resolve):
     SPRANG_DIR=$(realpath ~/tools/sprang)
     mkdir -p .devin
     cat > .devin/config.json << EOF
{
  "mcpServers": {
    "sprang": {
      "command": "node",
      "args": ["$SPRANG_DIR/packages/mcp/dist/server.js"],
      "env": { "SPRANG_ROOT": "\${workspaceFolder}" }
    }
  }
}
EOF

   Workflows — all /sprang-* slash commands:
     mkdir -p .windsurf/workflows .devin/workflows
     cp ~/tools/sprang/.windsurf/workflows/*.md .windsurf/workflows/
     cp ~/tools/sprang/.windsurf/workflows/*.md .devin/workflows/

   Skills:
     mkdir -p .windsurf/skills .devin/skills
     cp -r ~/tools/sprang/.windsurf/skills/sprang* .windsurf/skills/
     cp -r ~/tools/sprang/.windsurf/skills/sprang* .devin/skills/

5. Run the initial scan of this project (Phase 1 — fully static, under 60s):
   sprang scan . --phase1-only

6. Start the dashboard:
   sprang open .
   Dashboard will be at http://localhost:7777

7. Install the cascade-messaging VS Code extension (enables the Ask Agent panel in the dashboard):
   if ! windsurf --list-extensions 2>/dev/null | grep -q cascade-messaging; then
     windsurf --install-extension ~/tools/sprang/cascade-messaging-0.1.0.vsix 2>/dev/null || \
     code --install-extension ~/tools/sprang/cascade-messaging-0.1.0.vsix 2>/dev/null || \
     echo "Manual install: Extensions → Install from VSIX → ~/tools/sprang/cascade-messaging-0.1.0.vsix"
   fi

8. Report what was installed and where. Then tell me:
   "Setup complete. Please reload the window now (Cmd/Ctrl+Shift+P → Reload Window)
   so the MCP server and cascade-messaging extension activate.
   Dashboard is live at http://localhost:7777.
   Once reloaded, type /sprang-onboard to begin."

After the agent finishes, reload the window (Cmd/Ctrl+Shift+PReload Window), then type /sprang-onboard. Dashboard is at http://localhost:7777.


Installer script

For scripted or manual setup on any platform:

# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/FavioVazquez/sprang/main/install.sh | bash -s windsurf
# Options:  windsurf  |  copilot  |  claude
# Windows (PowerShell)
irm https://raw.githubusercontent.com/FavioVazquez/sprang/main/install.ps1 | iex
# Options:  .\install.ps1 windsurf  |  .\install.ps1 copilot  |  .\install.ps1 claude
# If you already have the repo cloned:
./install.sh windsurf     # symlinks 11 skills into ~/.windsurf/skills/
./install.sh copilot      # symlinks 11 skills into ~/.copilot/skills/
./install.sh claude       # prints per-project setup guide
./install.sh --update     # pull latest + rebuild
./install.sh --uninstall windsurf

| Flag | Skills target | Platform | |---|---|---| | windsurf | ~/.windsurf/skills/ | Windsurf AI / Devin Desktop | | copilot | ~/.copilot/skills/ | GitHub Copilot (or use gh skill install FavioVazquez/sprang) | | claude | project-local | Claude Code (plugin marketplace or manual copy — see guide printed by installer) |


Contents


What Sprang does

Sprang gives your AI agent a persistent memory of the codebase — not just file names and symbols, but the full context of why things exist, who changed them, what they risk, and how they connect.

One-call answers

# "What will break if I change auth.ts?"
sprang_diff_impact { files: ["src/auth.ts"] }
→ 14 impacted nodes, top risk: api-gateway.ts (0.91), session.ts (0.78)

# "Why does this file exist?"
sprang_why { node_id: "src/auth.ts" }
→ 23 commits, 3 authors, PR #441 "add JWT refresh flow", churn: 8/90d

# "Show me the riskiest parts of this codebase"
sprang_health {}
→ god_node: 2, circular_dependency: 1, unstable_interface: 3
  top risk: auth.ts (0.82), api.ts (0.71), db/pool.ts (0.68)

# "Walk me through the architecture"
/sprang-onboard
→ 8-step guided tour, persona-adaptive (non-technical / pm / junior / senior)

Capabilities

| Capability | How | |---|---| | Git decision context | git-layer — who changed each file, why, PR references, change frequency | | Code smell detection | smell-detector — deterministic heuristics, zero LLM calls | | Function call graph | file-analyzer — function-to-function calls edges, internal/external call counts, unused-function detection | | Design pattern detection | 9 patterns — singleton, factory, observer, strategy, decorator, react_hook, context_provider, event_emitter, dependency_injection | | Layer violation detection | architecture-analyzer — flags lower layers importing from higher ones (e.g. data → ui) | | Risk scoring | risk-scorer — blast radius × coupling × test gap × churn, 0.0–1.0 per node | | Instant point-and-analyze | Dashboard landing screen — type a local path or paste a GitHub URL, Phase 1 runs with no agent and no API key | | Guided tours | tour-builder — BFS-ordered pedagogical paths through the codebase | | Domain map | domain-analyzer — directory cohesion clustering into named business layers | | Blast-radius diff | sprang_diff_impact — BFS over the graph before any edit, risk-ranked | | Team annotations | sprang_annotate — write .sprang/annotations/<id>.md, committed to the repo | | Knowledge graphs | /sprang-knowledge — Obsidian / Logseq / Dendron / Foam / Zettelkasten / plain markdown | | 11 slash commands | Full workflow coverage for Windsurf/Devin Desktop and Claude Code | | 9 MCP tools | Direct graph access — all agents read and write the graph via MCP | | < 60s skeleton | Phase 1 is fully static — runs anywhere, no network, no waiting | | Architecture card view | React Flow + ELK layer map — one card per layer, weighted cross-layer edges | | Structural fingerprinting | SHA-256 + signature extraction — SKIP/COSMETIC/STRUCTURAL per file | | Language lessons | 12 programming pattern detectors attached to tour steps and graph nodes | | Semantic search | Cosine similarity + TF-IDF fallback — sprang_query mode:"semantic" | | Auto-update hooks | sprang install-hooks or native Claude Code hooks — incremental refresh after every commit | | 12 languages | TypeScript, JavaScript, Python, Go, Rust, Java, Kotlin, Ruby, PHP, C, C++, C# — plus Markdown for knowledge graphs | | Live dashboard | Sigma.js force-directed graph, risk heatmap, diff overlay, BFS pathfinder, tour player |

What existing tools don't do

| | Sprang | Grep / LSP | LLM context | Sourcegraph | |---|---|---|---|---| | Locate code | ✅ | ✅ | ✅ | ✅ | | WHY this file exists | ✅ git history + annotations | — | sometimes | — | | Blast radius before an edit | ✅ BFS in one call | — | approximate | — | | Risk score per node | ✅ deterministic formula | — | subjective | — | | Persistent across sessions | ✅ graph on disk | ✅ files | ❌ ephemeral | ✅ | | Agent-readable (MCP) | ✅ 9 tools | — | via context | partial | | Works offline, no API key | ✅ Phase 1 | ✅ | ❌ | ❌ | | Knowledge bases (Obsidian etc.) | ✅ | — | — | — | | Team annotations committed to repo | ✅ | — | — | ✅ (notebooks) |

The key insight: your AI agent is already excellent at reasoning — it just needs the right data. Sprang provides that data layer so the agent doesn't have to reconstruct it from scratch on every conversation.


Workflows in practice

Day 1 at a new company

# Build the skeleton in 60 seconds — no API key needed
sprang scan . --phase1-only

# Open the dashboard
sprang open .

# Ask for a guided architecture tour
/sprang-onboard
# → 8-step tour, adapts to your role (junior / senior / PM / non-technical)

# Find the highest-risk areas before you touch anything
/sprang-health
# → health grade B, top risks: auth.ts (0.82), api-gateway.ts (0.71)
# → circular dependency: services/cache.ts ↔ services/session.ts

Before refactoring a module

# Check what depends on the file you want to change
sprang_diff_impact { files: ["src/payments/processor.ts"] }
# → 18 impacted nodes. High risk: checkout.ts (0.88), invoice.ts (0.79)

# Read the git history before touching anything
sprang_why { node_id: "src/payments/processor.ts" }
# → 31 commits, PR #892 "stripe 3DS — do not simplify retry logic"
#    12 changes in 90 days, 2 primary authors

# Ask why it's built the way it is
/sprang-chat "Why is the retry logic in processor.ts so complex?"
# → "PR #892 added Stripe 3DS authentication. The retry loop handles partial auth states
#    that Stripe returns mid-payment. Simplifying it would break 3DS flows."

PM review — "what does the checkout service do?"

# Explore the business domain without reading code
/sprang-domain checkout
# → Domain: Checkout
#   Flows: product_selection → cart_management → payment_processing → confirmation
#   Entry points: CartService, CheckoutController, PaymentGateway

# Non-technical persona tour
/sprang-onboard
# → "Selecting non-technical mode..."
#   Step 1: What Checkout does in plain English
#   Step 2: The 4 flows that make up a transaction
#   Step 3: What the team considers risky (and why)

Reviewing a risky PR

# See what the PR touches and how risky those files are
/sprang-diff src/auth/session.ts src/auth/jwt.ts
# → diff-overlay written → open dashboard → amber nodes show impact zone

sprang_diff_impact { files: ["src/auth/session.ts", "src/auth/jwt.ts"] }
# → 22 impacted nodes. session.ts risk: 0.87 → review carefully
#   Downstream: api-gateway.ts, user-service.ts, admin-panel.ts

sprang_why { node_id: "src/auth/session.ts" }
# → 14 changes in 90 days, 4 authors, PR #321 "enterprise SSO session timeout"
#    Note: changes here broke SSO twice before (see annotation)

Exploring an Obsidian vault

/sprang-knowledge /path/to/your/vault
# → 847 notes, 2,341 connections, 12 topic clusters

sprang open /path/to/vault
# → Force-directed graph of all your notes
# → Color by topic cluster
# → Click any note to see backlinks, frontmatter, tags
# → ReadingPanel: scroll the full article in the sidebar

# Find conceptual neighbors you didn't know were connected
sprang query "regularization techniques" --semantic
# → L2 weight decay, dropout, batch normalization, early stopping, data augmentation

Platform architecture

packages/
├── core/       Pipeline: 9 agents, schema, watcher, graph store, fingerprinting, semantic search
├── cli/        sprang scan | health | query | watch | status | install-hooks | merge | open | diagram
├── mcp/        stdio MCP server — 9 tools for all AI platforms
└── dashboard/  React + Vite + Sigma.js — 7 views (Graph/Health/Domains/Architecture/Treemap/Matrix/Learn)
graph LR
    CLI["sprang (CLI)"] --> CORE["@sprang/core"]
    MCP["@sprang/mcp"] --> CORE
    DASH["@sprang/dashboard"] -->|"fetches knowledge-graph.json"| FS["filesystem (.sprang/)"]
    CORE --> FS
    MCP --> FS

    CASCADE["Windsurf / Devin Desktop\n(mcp_config.json or .devin/config.json)"] -->|"MCP tools"| MCP
    CASCADE -->|"slash commands / skills"| CLI

    CLAUDE["Claude Code\n(.mcp.json)"] -->|"MCP tools"| MCP
    CLAUDE -->|"slash commands (.claude/commands/)"| CLI

    COPILOT["GitHub Copilot\n(.vscode/mcp.json)"] -->|"MCP tools"| MCP

Prerequisites

Required

| Tool | Min version | Install | Why | |---|---|---|---| | Node.js | 20 | nodejs.org or nvm install 20 | Runs the CLI, MCP server, and dashboard | | pnpm | 10 | npm install -g pnpm or corepack enable && corepack prepare pnpm@latest | Package manager (enforced in package.json) | | Git | 2.x | git-scm.com | git-layer agent reads commit history; scan works without it but decision context is unavailable | | Python 3 | 3.8 | Pre-installed on macOS/Linux; python.org on Windows | merge.py assembles chunk files into knowledge-graph.json; Windsurf hook save-conversation.py uses it too. No third-party packages — stdlib only. |

Verify your environment:

node --version    # must be v20.x or higher
pnpm --version    # must be 10.x or higher
git --version     # any modern version
python3 --version # 3.8 or higher (python3 on macOS/Linux, python on Windows)

Platform-specific

| Tool | Required for | Install | |---|---|---| | GitHub CLI 2.90.0+ (gh) | gh skill install (Copilot) | cli.github.com | | Playwright Chromium | e2e tests only — not for using the platform | Auto-installed by pnpm --filter @sprang/dashboard test:e2e |

No API key needed

Sprang does not call any AI API directly. The LLM is your agent (Claude Code, Windsurf / Cascade, or Copilot) — it reads the knowledge graph through MCP tools and applies its own intelligence. Phase 1 (static analysis) runs fully offline.


Manual build

If you've cloned the repo and want to build without using the installer:

cd ~/tools/sprang   # or wherever you cloned to

pnpm install        # install all dependencies
pnpm build          # build all packages

# Link the CLI globally
cd packages/cli
pnpm setup
export PNPM_HOME="$HOME/.local/share/pnpm"
export PATH="$PNPM_HOME:$PATH"
pnpm link --global
cd ../..

which sprang        # verify: should print $PNPM_HOME/sprang
sprang --version    # 0.2.4
# Start the dashboard (serves pre-built dist/, instant startup)
SPRANG_ROOT="/path/to/your/project" pnpm --filter @sprang/dashboard preview
# Open http://localhost:7777

CLI usage

# Phase 1 — static analysis, < 60s, builds the skeleton graph
sprang scan /path/to/your/project --phase1-only

# Full scan — Phase 1 now + Phase 2 enrichment via your AI agent
sprang scan /path/to/your/project

# Skip scan if graph is already current (compares git HEAD vs stats.gitCommitHash)
sprang scan . --phase1-only --if-stale

# Install a post-commit git hook that auto-refreshes the graph after each commit
sprang install-hooks

# Check graph age, phase, and node/edge count
sprang status

# Print health report: smells, risk table, orphans, circular deps
sprang health

# Search nodes by name or summary
sprang query "authentication"
sprang query "authentication" --semantic   # cosine similarity over TF-IDF embeddings

# Watch for file changes and incrementally update the graph
sprang watch

# Open the dashboard for any local folder — shows landing screen if no graph yet
sprang open /path/to/any/project
sprang open /path/to/any/project --port 8080
# Auto-trigger Phase 1 scan without clicking the button
sprang open /path/to/any/project --auto-scan
# Or open standalone — dashboard landing lets you type a path or paste a GitHub URL
sprang open

# Generate a Mermaid architecture diagram from the graph
sprang diagram
sprang diagram --output architecture.md

Output written to .sprang/ in your project root:

your-project/
└── .sprang/
    ├── knowledge-graph.json   ← main graph (nodes, edges, risk scores, smells)
    ├── SPRANG_REPORT.md       ← human-readable architecture summary
    ├── annotations/           ← agent-written node annotations (commit these)
    ├── config.json            ← optional thresholds + excludes
    └── intermediate/          ← Phase 2 progress (gitignored)

Windsurf / Devin Desktop — detailed setup

The fastest path is the agentic install prompt above. For manual step-by-step control:

1 — Build and scan

cd ~/tools/sprang && pnpm install && pnpm build
sprang scan /path/to/your/project --phase1-only

2 — Add the MCP server

For Windsurf — add to ~/.codeium/windsurf/mcp_config.json (merge if the file exists):

{
  "mcpServers": {
    "sprang": {
      "command": "node",
      "args": ["/absolute/path/to/sprang/packages/mcp/dist/server.js"],
      "env": { "SPRANG_ROOT": "/absolute/path/to/your/project" }
    }
  }
}

${workspaceFolder} is not resolved in this file — use full absolute paths.

For Devin Desktop — add to .devin/config.json in your project root instead:

{
  "mcpServers": {
    "sprang": {
      "command": "node",
      "args": ["/absolute/path/to/sprang/packages/mcp/dist/server.js"],
      "env": { "SPRANG_ROOT": "${workspaceFolder}" }
    }
  }
}

In .devin/config.json, ${workspaceFolder} is resolved automatically.

3 — Copy workflows, skills, and rules

mkdir -p .windsurf/workflows .windsurf/skills .windsurf/rules .devin/rules
cp /path/to/sprang/.windsurf/workflows/*.md .windsurf/workflows/
cp -r /path/to/sprang/.windsurf/skills/sprang* .windsurf/skills/
cp /path/to/sprang/.devin/rules/*.md .devin/rules/
cp /path/to/sprang/.windsurf/rules/*.md .windsurf/rules/
ln -sf ../.windsurf/workflows .devin/workflows
ln -sf ../.windsurf/skills .devin/skills

4 — Start the dashboard

SPRANG_ROOT="$(pwd)" pnpm --filter @sprang/dashboard preview
# Opens at http://localhost:7777

Open in your system browser (Chrome/Firefox) at http://127.0.0.1:7777 — not the IDE's embedded preview. The embedded Windsurf/Devin proxy does not forward /knowledge-graph.json and other middleware routes.

Important — start the server from a Windsurf / Devin Desktop terminal. Bridge detection uses three signals (any one is sufficient):

  1. WINDSURF_CASCADE_TERMINAL_KIND env var — automatically present in all IDE terminals
  2. .sprang/.cascade-bridge-active — written by the cascade-messaging extension on activation (works even if the server was started outside the IDE)
  3. .cascade-trigger-session exists — legacy fallback

If the server is started outside the IDE (e.g. via SSH without the env) and the extension hasn't written the marker yet, the bridge falls through to Claude Code or Copilot CLI if those are installed.

5 — Install the cascade-messaging extension

Enables persistent chat from the Sprang dashboard with context across Cascade sessions.

windsurf --list-extensions 2>/dev/null | grep -q cascade-messaging && echo "already installed" || \
  windsurf --install-extension /path/to/sprang/cascade-messaging-0.1.0.vsix

Or: ExtensionsInstall from VSIXcascade-messaging-0.1.0.vsix.

6 — Reload and run onboarding

Reload (Cmd/Ctrl+Shift+PReload Window) to activate the MCP server, then:

/sprang-onboard

What the agent does automatically

With .devin/rules/ files present, your agent will:

  • Before editing any file — call sprang_node to check risk_score and structural_warnings
  • On high-risk files (risk > 0.7) — call sprang_why to read decision context first
  • After changes — call sprang_diff_impact to assess blast radius

Driven by sprang-context.md (always-on) and sprang-highrisk.md (glob: *.ts, *.tsx, packages/*/src).


Ask Agent (dashboard chat)

The Ask Agent panel in the Sprang dashboard lets you ask questions about your codebase and see answers inline — routed through whichever AI agent is active. The bridge auto-detects the available agent at each request.

Bridge priority

| Priority | Agent | How it works | |---|---|---| | 1 | Windsurf / Devin Desktop | Writes to .cascade-trigger-session — the cascade-messaging VS Code extension forwards it to Cascade (the Windsurf AI), which calls sprang_respond MCP tool to write the reply. Async (poll). | | 2 | Claude Code (claude CLI) | Spawns claude -p "<question>" --output-format json non-interactively. Session ID persisted to .sprang/claude-session.json — resumes previous conversation via --resume. Sync. | | 3 | GitHub Copilot CLI (copilot) | Spawns copilot --prompt "<question>" --output-format json non-interactively. Uses --resume=<session-id> for session continuity once a session exists. Sync. | | — | None | Panel shows instructions to install one of the above. |

The active bridge is shown below the "Ask Agent" header (via Claude Code, via Copilot CLI, via Windsurf).

Session files (gitignored)

| File | Purpose | |---|---| | .sprang/cascade-response.json | Response written by sprang_respond MCP tool or by the CLI bridge; polled by dashboard | | .sprang/claude-session.json | Persisted Claude Code session ID for --resume | | .sprang/copilot-session.json | Persisted Copilot CLI session ID for --resume=<id> | | .cascade-trigger-session | Written by dashboard Windsurf bridge, read by cascade-messaging extension |

Windsurf / Devin Desktop setup

| Setting | Default | Description | |---|---|---| | cascade-messaging.triggerFile | .cascade-trigger-session | Trigger file path relative to workspace root | | cascade-messaging.autoStart | true | Start watcher automatically on activation |

Important: the SPRANG_ROOT in ~/.codeium/windsurf/mcp_config.json and the SPRANG_ROOT you pass to pnpm preview must point at the same project. The MCP server writes cascade-response.json to SPRANG_ROOT/.sprang/ and the dashboard reads it from the same path. If they differ, responses will be written to one project but never appear in the other's dashboard. Update mcp_config.json and restart the MCP server whenever you switch projects.


Slash commands

Available in Windsurf / Cascade, Devin Desktop, and Claude Code:

| Command | Description | |---|---| | /sprang | Build or refresh the knowledge graph — auto-detects codebase vs knowledge base | | /sprang-analyze [path] [--full] [--language <lang>] [--chunk N] | Full AI-driven analysis — summaries, layers, tour, risk | | /sprang-knowledge [path] [--format obsidian\|logseq\|...] [--full] | Build knowledge graph from markdown notes | | /sprang-chat <question> | Ask any question about the codebase | | /sprang-explain <file> | Deep-dive: what, why, who, risk, history for a file or function | | /sprang-onboard | Guided architecture tour — adapts to persona (non-technical / pm / junior / senior) | | /sprang-diff [files...] | Blast radius analysis — writes diff overlay for dashboard | | /sprang-domain [name] | Explore business domain architecture and flows | | /sprang-why <file> | Git history + rationale + team annotations for a file | | /sprang-health | Full health report: risk, smells, orphans, circular deps | | /sprang-team [node] | Browse/write team annotations with staleness detection |


Two-phase pipeline

flowchart TB
    subgraph Phase1 ["Phase 1 — Skeleton (< 60s, fully static)"]
        PS[project-scanner] --> FA[file-analyzer]
        FA --> SG[skeleton graph written]
    end
    subgraph Phase2 ["Phase 2 — Enrichment (deterministic agents, or via /sprang-analyze)"]
        SM[smell-detector] --> FG[final graph + SPRANG_REPORT.md]
        SEC[security-scanner] --> FG
        G3[git-layer] --> RS[risk-scorer]
        G1[architecture-analyzer] --> TB[tour-builder]
        G2[domain-analyzer] --> TB
        RS --> FG
        TB --> GR[graph-reviewer]
        GR --> FG
    end
    SG -->|"forks Phase 2"| Phase2

Phase 1 is just project-scanner + file-analyzer — the structural skeleton (files, functions, import/call edges). All structural warnings, risk scores, security findings, layers, tours, and domains are populated in Phase 2 (so a --phase1-only scan produces none of them yet). Phase 2's agents are deterministic and run without an API key; /sprang-analyze additionally layers in your agent's semantic summaries.

Your AI agent is the intelligence layer. Phase 2 enrichment is performed by the agent using its own context window — it reads the graph, writes summaries, and calls sprang_annotate to record what it learns. No external API.


The three differentiating agents

git-layer — Decision context from version history

git log --follow --format="%H|%ae|%ai|%s" -- <filepath>
   ↓
associate commits to nodes via line-range diff hunk headers
   ↓
node.decision_context: { commits, primary_authors, last_changed,
                          change_frequency, rationale_snippets, pr_references }

smell-detector — 10 deterministic heuristics, no LLM calls

| Smell | Trigger | |---|---| | god_node | out_degree > 20 OR cyclomatic_sum > 200 | | circular_dependency | Johnson's cycle detection, cycles ≤ 6 nodes | | duplicate_logic | Same param_count + complexity_bucket + ≥2 shared callers | | unclear_coupling | Two modules share > 40% import targets, no direct edge | | low_cohesion | Functions referenced by ≥3 distinct domains, < 50% same top domain | | unstable_interface | change_frequency > 10/90d AND in_degree > 5 | | orphan_node | in_degree=0 AND out_degree=0 AND not entry point | | over_connected | total_degree (in + out) > 30 | | name_duplicate | Same symbol name defined in ≥2 files | | layer_violation | Lower layer imports from a higher one (e.g. data → ui) — from architecture-analyzer |

risk-scorer — Composite formula

risk_score = clamp(
  blast_radius  × 0.35   ← BFS reachable dependents / total nodes
  + coupling    × 0.25   ← (in+out degree)/40, +0.2 if in cycle
  + test_gap    × 0.25   ← 0.0 if tested, 0.5+blast×0.5 if not
  + churn       × 0.15,  ← change_frequency/20
  0.0, 1.0
)

MCP tools

| Tool | Input | Output | |---|---|---| | sprang_node | { node_id } | Full node + 1-hop neighbors + layer + in/out degree + annotation status | | sprang_query | { query, node_types?, limit?, mode? } | Fuzzy or semantic-ranked nodes with summaries | | sprang_diff_impact | { files: string[] } | BFS blast-radius, risk-ranked impact list | | sprang_why | { node_id } | Decision context + git history + team annotation | | sprang_health | {} | Health grade (A–F), score (0–100), security summary, top-10 risk, smells, orphans, circular deps, run history | | sprang_tour | { tour_id?, persona? } | Ordered pedagogical tour — persona: junior (all steps) / senior or experienced (skip intro) / pm (domain/service nodes) / non-technical (entry-points and domains only) | | sprang_domain | { domain_name? } | Business domain flows and entry points | | sprang_annotate | { node_id, content, tags? } | Write .sprang/annotations/<id>.md | | sprang_respond | { response, question? } | Write response to .sprang/cascade-response.json for dashboard display |

sprang_query accepts mode: "semantic" for cosine similarity search over TF-IDF embeddings.

Tour personas

sprang_tour and /sprang-onboard support four audience personas. The dashboard PersonaSelector sets the active persona for the Learn view.

| Persona | Alias | Audience | Tour filter | |---|---|---|---| | junior | — | Developer new to this codebase | All steps with language lessons | | senior | experienced | Experienced engineer | Skips the introductory step, focuses on coupling and risk | | pm | — | Product manager | Domain and service nodes only — business capability focus | | non-technical | — | Executive / business stakeholder | Entry-points and domain nodes only — no implementation details |

Default: junior when no persona is specified.

Health grade (v0.2.1)

sprang_health now returns a letter grade (A–F) computed from five deterministic penalty categories:

| Penalty | Max | Trigger | |---|---|---| | dead_code_penalty | 20 pts | orphan nodes (isolated — no imports, not an entry point) | | circular_penalty | 20 pts | circular dependency chains | | god_node_penalty | 15 pts | god_node smells (out_degree > 20) | | coupling_penalty | 15 pts | over_connected smells (total_degree > 30) | | security_penalty | 20 pts | hardcoded secrets, SQL injection, XSS patterns, and 5 other regex categories |

health_score = 100 − Σ(penalties)   → A ≥ 90, B ≥ 80, C ≥ 70, D ≥ 60, F < 60

security_summary groups findings by severity (high / medium / low) and by category (hardcoded_secret, sql_injection, xss_risk, unsafe_eval, unsafe_exec, unsafe_deserialization, path_traversal, weak_crypto). All 20 detection patterns are deterministic regex — no LLM calls.

history returns the last 30 sprang_health snapshots from .sprang/intermediate/health-history.jsonl so you can track whether code quality is improving or degrading over time.

Enriched sprang_node response

{
  "node": { "id": "...", "type": "file", "summary": "...", "risk_score": 0.72 },
  "neighbors": [{ "node_id": "...", "direction": "outgoing", "edge_type": "imports" }],
  "layer": { "id": "layer:services", "name": "Services" },
  "layer_mate_count": 7,
  "in_degree": 4,
  "out_degree": 11,
  "has_annotation": true,
  "annotation_path": ".sprang/annotations/src-auth-ts.md"
}

Agent interaction flow

sequenceDiagram
    participant D as Developer
    participant C as AI Agent
    participant M as sprang-mcp
    participant F as filesystem

    D->>C: /sprang-onboard
    C->>M: sprang_health {}
    M-->>C: { smells, risk_top10, orphans }
    C->>M: sprang_why { node_id: "src/auth.ts" }
    M-->>C: { decision_context, commits, pr_references }
    C->>D: "High-risk nodes: auth.ts (0.82), api.ts (0.71)..."
    D->>C: "Annotate auth.ts — this is the session validation layer"
    C->>M: sprang_annotate { node_id, content }
    M->>F: .sprang/annotations/src-auth-ts.md

Dashboard

Important: always run these commands from the Sprang monorepo directory (~/tools/sprang or wherever you cloned it), not from your project directory. SPRANG_ROOT points at your project; the server lives in the Sprang repo.

# Production preview — pre-built dist/, instant startup — recommended for daily use
cd ~/tools/sprang
SPRANG_ROOT=/path/to/your/project pnpm --filter @sprang/dashboard preview
# Opens at http://localhost:7777

# Development — live reload (use when working on the dashboard itself)
cd ~/tools/sprang
SPRANG_ROOT=/path/to/your/project pnpm --filter @sprang/dashboard dev
# Opens at http://localhost:7338

Which one to use?

  • preview — use this for normal codebase analysis. Serves the pre-built dist/ folder, starts instantly, port 7777. After pulling a Sprang update you must rebuild before restarting preview — see below.
  • dev — use this only if you are modifying dashboard source code. Vite hot-reloads source changes automatically, port 7338. No rebuild needed for source changes, but the /knowledge-graph.json middleware still reads from SPRANG_ROOT at runtime — it always serves the latest graph on disk.

After pulling a Sprang update — rebuild before using preview:

cd ~/tools/sprang
git pull --ff-only
pnpm install && pnpm build   # rebuilds dist/ — required for preview to pick up changes
SPRANG_ROOT=/path/to/your/project pnpm --filter @sprang/dashboard preview

dev vs preview and the knowledge graph: Both modes read SPRANG_ROOT/.sprang/knowledge-graph.json live from disk via the Vite middleware — they always show the latest graph without any rebuild. The difference is only in the dashboard UI code itself: preview serves the last compiled dist/, dev compiles on the fly.

Open in your system browser, not the IDE's embedded browser. Windsurf/Devin Desktop's embedded preview proxy (127.0.0.1:4xxxx) does not forward the custom middleware routes (/knowledge-graph.json, /bridge-status, etc.). Always open http://127.0.0.1:7777 directly in Chrome or Firefox.

Instant analysis — point and go (no agent, no API key)

Open the dashboard on a project that has not been scanned yet and you land on an analyze screen: type a local path or paste a GitHub URL and Phase 1 runs immediately — fully static, under 60 seconds, no agent and no API key. GitHub repos are shallow-cloned to a temp folder and never stored.

sprang open                            # standalone — type any path or paste a GitHub URL
sprang open /path/to/project --auto-scan   # start Phase 1 the moment the browser opens

The single input auto-detects local path vs. GitHub URL (github.com/owner/repo, owner/repo, or the full URL) and shows a live Local / GitHub badge. This is the zero-friction entry point — Phase 2 enrichment (semantic summaries, decision context, risk) then layers in via your agent. Once a graph is loaded, the New analysis button in the nav returns you to this screen to analyze another project.

Views

| View | Key | Description | |---|---|---| | Graph | g / 1 | Sigma.js force-directed canvas — risk heatmap, layer filter, diff overlay, BFS pathfinder | | Health | h / 2 | Smell breakdown, top-10 risky nodes, circular deps, orphan count | | Domains | d / 3 | Business domain explorer — list view + React Flow layout toggle | | Architecture | a / 4 | React Flow + ELK layer map — one card per layer, weighted cross-layer edge count | | Treemap | t / 5 | D3 treemap — file/folder hierarchy sized by lines, colored by risk score | | Matrix | m / 6 | Adjacency matrix — file-to-file dependency grid, sorted by layer rank | | Learn | l / 7 | Persona-adaptive guided tour with language lessons per step |

Keyboard shortcuts

| Key | Action | |---|---| | Cmd/Ctrl+K | Open node search | | Esc | Close panel / search | | g / 1 | Graph view | | h / 2 | Health view | | d / 3 | Domains view | | a / 4 | Architecture view | | t / 5 | Treemap view | | m / 6 | Matrix view | | l / 7 | Learn view | | r | Toggle risk overlay | | ? | Keyboard shortcuts help |

| Component | Role | |---|---| | FilterPanel | Filter nodes by category, complexity, risk level, edge type | | DiffToggle | Load .sprang/diff-overlay.json → amber/warm-gray blast radius | | PathFinder | BFS shortest path between any two nodes | | ExportMenu | Export graph as JSON, Markdown, clipboard, or SVG | | FileExplorer | File tree with search; double-click opens CodeViewer | | CodeViewer | Prism syntax highlighting with line-range jump | | PersonaSelector | Business (non-technical) / Product (pm) / Learn (junior) / Deep Dive (senior) | | KnowledgeInfo | Right sidebar for knowledge graphs: backlinks, frontmatter, tags | | ReadingPanel | Slide-up reading overlay for article nodes | | ThemePicker | Dark / Light / High-contrast (persisted to localStorage) | | LayerLegend | Layer color swatches; hover highlights all nodes in that layer | | NodeTooltip | Mouse-following tooltip: type, label, summary, risk score | | KeyboardShortcutsHelp | ? opens shortcut reference modal | | OnboardingOverlay | 4-step first-run guide (dismissed after first visit) | | MobileBottomNav | Bottom nav on screens < 768px | | BreadCrumb | Layer → Node drill-down above the graph panel |


Knowledge graphs

/sprang-knowledge [path] builds a kind: "knowledge" graph from markdown notes — Obsidian vaults, Logseq databases, Dendron workspaces, Foam wikis, Zettelkasten archives, or plain markdown.

/sprang-knowledge /path/to/your/notes

Produces:

  • Article nodes — one per .md file, with summary, tags, knowledgeMeta
  • Topic / entity nodes — inferred from MOC pages, wikilinks, frontmatter
  • Edgescites, builds_on, contradicts, exemplifies, categorized_under, authored_by
  • Topic clusters — analogous to architecture layers
  • Reading tour — recommended reading order from most-connected note outward

The dashboard auto-switches to knowledge mode: KnowledgeInfo sidebar, ReadingPanel overlay, reading order in the Learn tab.


Graph schema

interface SprangNode {
  id: string;           // "file:src/auth.ts" | "function:src/auth.ts:validate"
  label: string;
  type: NodeType;       // 16 types: file | function | class | service | ...
  summary?: string;
  layer?: string;
  complexity?: 'simple' | 'moderate' | 'complex';
  location?: { file: string; start_line?: number; end_line?: number };

  decision_context?: {
    commits: CommitRef[];
    primary_authors: string[];
    last_changed: string;        // ISO-8601
    change_frequency: number;    // commits in last 90 days
    rationale_snippets: string[];
    pr_references: string[];
  };

  structural_warnings?: Array<{
    category: SmellCategory;     // 10 categories
    severity: 'low' | 'medium' | 'high';
    description: string;
    related_node_ids: string[];
    heuristic: string;
  }>;

  risk_score?: number;           // 0.0–1.0
  risk_factors?: RiskFactor[];   // blast_radius | coupling | test_gap | churn | ...
  knowledgeMeta?: {              // knowledge graphs only
    wikilinks: string[];
    backlinks: string[];
    category: string;
  };
}

Annotations are stored as .sprang/annotations/<node-id>.md with YAML frontmatter — commit these files so team knowledge persists across sessions.


Live watcher

sprang watch uses chokidar with:

  • awaitWriteFinish: { stabilityThreshold: 800ms } — no spurious saves
  • 2s debounce collecting changed files into a batch
  • SHA-256 fingerprinting — skips unchanged-content saves
  • Incremental: re-analyzes changed files + 1-hop import neighbors only
  • Atomic write: .tmp → rename — crash-safe

Development

pnpm install
pnpm build             # build all packages
pnpm test              # 689 unit tests across core/dashboard/mcp/cli
pnpm typecheck         # strict TypeScript, zero errors
pnpm --filter @sprang/dashboard dev        # dashboard at http://localhost:7338
pnpm --filter @sprang/dashboard test:e2e          # 64 Playwright UI e2e tests
pnpm --filter @sprang/dashboard test:e2e:bridge   # 8 platform-bridge e2e tests (mock claude/copilot CLIs)

Test summary

| Package | Runner | Tests | What is tested | |---|---|---|---| | @sprang/core | Vitest | 464 | Schema, agents, pipeline, fingerprinting, language lessons, normalization, semantic search, worktree, health-grade, similarity, call graph, layer violations, Phase 2 security-scanner wiring, enrichment preservation, tour robustness, domain naming | | @sprang/dashboard | Vitest | 85 | Zustand store (26), BFS pathfinder (7), ArchitectureView logic (9), edge-aggregation (7), elk-layout (6), bridge detection (30) | | @sprang/mcp | Vitest | 67 | GraphLoader + invalid-graph diagnostic (5), sprang_node + sprang_annotate (11), 6 MCP tools (40), sprang_respond (8), sprang_query enhancements (3) | | sprang (CLI) | Vitest | 73 | init --platform scaffolding for all 3 agents (5), --if-stale scan flag (3), install-hooks command (4), query tokenization (3), merge.py schema normalization (6), merge command + sprang merge normalization (10), hook scripts end-to-end (12), platform parity across Claude Code, Windsurf/Devin, Copilot (22), Windsurf save-conversation.py hook real execution (8) | | Total unit | | 689 | | | @sprang/dashboard | Playwright | 64 | Full UI e2e — loading, landing screen (path/GitHub URL), nav, keyboard shortcuts (all 1–7/g/h/d/a/t/m/l), architecture tab, treemap/matrix tabs + empty states, cascade bridge, health grade (A–F), security findings, risk overlay, analyze endpoint, tour player, persona selector | | @sprang/dashboard | Playwright (bridge) | 8 | Platform bridge e2e with mock claude/copilot CLIs on PATH — real spawn → parse → session persist → response file for all 3 bridges: detection priority (windsurf marker > claude > copilot), --resume session continuity, --allowedTools MCP allowlist, Windsurf .cascade-trigger-session protocol, session clearing |

packages/core/tests/
├── schema/
│   └── validators.test.ts                  23 tests — Zod schema, round-trip serialization, security round-trip
├── agents/
│   ├── project-scanner.test.ts              6 tests — file discovery, language detection
│   ├── project-scanner-fingerprint.test.ts  6 tests — fingerprint stats, skip/structural detection
│   ├── file-analyzer.test.ts                5 tests — AST parsing, edge extraction
│   ├── smell-detector.test.ts              14 tests — circular-deps, god-node, clean baseline
│   ├── risk-scorer.test.ts                 15 tests — formula weights, factor tags
│   ├── tour-builder.test.ts                 3 tests — entry-point fallback, flat-tour robustness
│   ├── domain-analyzer.test.ts              3 tests — heuristic naming when the LLM returns empty
│   ├── git-layer.test.ts                    6 tests — commit association, PR refs
│   ├── architecture-analyzer.test.ts        8 tests — layer clustering
│   ├── language-lessons.test.ts            51 tests — 12 pattern detectors, positive + negative
│   ├── language-lessons-priority.test.ts   15 tests — priority ladder, multi-language
│   ├── multi-lang-imports.test.ts          50 tests — per-language import extraction + resolver
│   └── multi-lang-symbols.test.ts          34 tests — per-language symbol parsing
├── graph/
│   ├── normalize.test.ts                   17 tests — all 6 normalization steps
│   ├── merge-subgraphs.test.ts              9 tests — pnpm workspace, prefix namespacing
│   ├── preserve-enrichment.test.ts          3 tests — phase1-only keeps Phase 2 enrichment
│   └── normalize-assembled.test.ts          4 tests — coerce drifted agent output to schema-valid (shared by sprang merge + merge.py)
├── utils/
│   ├── fingerprint.test.ts                 28 tests — SHA-256, TS/Python/Go extraction, classifyChange
│   └── embedding-search.test.ts            26 tests — cosine similarity, TF-IDF, vocabulary
├── orchestrator/
│   ├── worktree.test.ts                      4 tests — worktree redirect, git-not-found
│   └── phase2-security.test.ts               2 tests — real Phase 1→2 pipeline, security_summary + warnings
└── integration/
    ├── pipeline.test.ts                     13 tests — full Phase 1 against simple-ts/ fixture
    ├── pipeline-python.test.ts               8 tests — full Phase 1 against simple-python/ fixture
    └── pipeline-multilang.test.ts           16 tests — Go, Rust, Java, Ruby, C, Kotlin pipelines

packages/dashboard/src/
├── store.test.ts                26 tests — Zustand store state transitions
└── pathfinder.test.ts            7 tests — BFS shortest path

packages/dashboard/src/pages/
└── ArchitectureView.test.ts      9 tests — empty-state detection, card count, edge aggregation

packages/dashboard/src/utils/
├── edge-aggregation.test.ts      7 tests — cross-layer counting, intra-layer exclusion
└── elk-layout.test.ts            6 tests — ELK mock, coordinate pass-through, fallback

packages/dashboard/e2e/
└── app.spec.ts                  64 tests — Playwright, full UI coverage
    ├── error state (no graph, retry button)
    ├── loaded state (all 7 nav tabs)
    ├── navigation (graph → health → domains → architecture → treemap → matrix → learn)
    ├── keyboard shortcuts (Ctrl+K, h, g, d, a, t, m, l, ?, 1-7, r — complete set)
    ├── health view (heading, god_node smell, health grade A–F badge, security findings)
    ├── domains view (domain label rendered)
    ├── search dialog (open, type, filter, close)
    ├── onboarding overlay (dismiss)
    ├── architecture view (empty state, layer count, card click, clear selection)
    ├── agent bridge (/agent-ask POST validation + success, /agent-response DELETE)
    ├── bridge status (/bridge-status → kind + detail shape, Ask Agent panel)
    ├── graph APIs (/knowledge-graph.json, /diff-overlay.json, /file-content.json)
    ├── risk overlay (R key toggles on/off)
    ├── analyze endpoint (/analyze POST trigger)
    ├── sigma canvas (present and non-zero size)
    ├── learn view (persona selector — all 4 options, tour start, step advance, exit)
    └── nav bar (logo + all 7 tabs persistent)

packages/mcp/tests/
├── graph-loader.test.ts          5 tests — load, null-on-missing, hot-reload, invalid-graph null, summarizeZodIssues diagnostic
├── sprang-node.test.ts          11 tests — sprang_node enrichment, sprang_annotate
└── mcp-tools.test.ts            38 tests — 6 MCP tools (health, tour, query, diff_impact, domain, why):
    ├── sprang_health  (7)  — counts, risk summary, smells, orphan detection
    ├── sprang_tour    (9)  — default/id, junior/senior/pm/non-technical/experienced persona, languageLesson
    ├── sprang_query   (9)  — label/summary match, empty, type filter, limit, mode:semantic
    ├── sprang_diff    (5)  — changed nodes, BFS blast radius, unknown files
    ├── sprang_domain  (4)  — list all, detail by name, unknown error
    └── sprang_why     (6)  — label/summary, decision_context, graceful no-context

packages/cli/tests/
├── commands/
│   ├── init.test.ts              5 tests — init --platform scaffolding (claude/copilot/windsurf MCP config + file copy, no worktree leak)
│   ├── scan-if-stale.test.ts     3 tests — hash-match skip, hash-mismatch scan, missing graph
│   ├── install-hooks.test.ts     4 tests — fresh creation, no-monorepo-path, append-to-existing, duplicate guard
│   ├── query.test.ts             3 tests — multi-word tokenization, single keyword, no-match
│   └── merge.test.ts            10 tests — chunk assembly, dict-as-array normalization, sprang merge schema normalization + risk-scores
├── merge-normalize.test.ts       6 tests — merge.py coerces drifted agent output to a schema-valid graph
├── hooks-scripts.test.ts        12 tests — session-start.sh and post-tool-use.sh via bash:
│   ├── session-start.sh (5): no-graph warning, fresh silence, stale hash display,
│   │                         missing-gitCommitHash silence, non-git-repo silence
│   └── post-tool-use.sh (7): non-git-command silence, no-graph silence, no-CLI silence,
│                              empty-input silence, merge detection, cherry-pick detection,
│                              no trigger on git status/log/diff/push
├── platform-parity.test.ts      22 tests — cross-platform integration invariants:
│   ├── manifests (10): all 6 JSON manifests parse, plugin versions match, skills paths
│   │                   resolve, MCP server dist referenced by .devin/.mcp/.vscode configs
│   ├── skills parity (4): same 11 skills in skills/ and .windsurf/skills/, frontmatter
│   │                      name+description, Windsurf trigger phrases, merge.py present
│   ├── workflows/commands (2): 11 .windsurf/workflows + 11 .claude/commands match skills
│   ├── rules parity (2): 3 rules byte-identical .windsurf ↔ .devin, names in .claude/rules
│   ├── hooks wiring (2): both hooks.json wire save-conversation.py; .claude/settings.json
│   │                     SessionStart/PostToolUse scripts exist and are executable
│   └── copilot extras (2): copilot-instructions.md lists all 9 MCP tools, .vsix artifact
└── windsurf-hook.test.ts         8 tests — save-conversation.py real execution via python3:
                                  happy path, last-exchange-only, multi-response join, append,
                                  missing transcript, malformed stdin, no workspace root,
                                  user input without response

packages/dashboard/e2e/
├── app.spec.ts                  64 tests — full UI e2e (chromium)
└── bridge.spec.ts                8 tests — platform bridges with mock claude/copilot CLIs:
    ├── claude (3): detection, spawn contract (-p/--output-format/--allowedTools incl.
    │               sprang_respond), JSON parse, session persist, --resume continuity
    ├── windsurf (1): marker-file priority over claude CLI, async mode,
    │                 .cascade-trigger-session protocol prefix, atomic write
    └── copilot (4): priority fall-through, JSONL parse, session persist,
                     --resume=<id> continuity, DELETE clears session

| Fixture | Purpose | |---|---| | simple-python/ | Python import edges, def/class nodes | | simple-go/ | Go func/struct nodes, block imports | | simple-rust/ | Rust fn/struct/enum nodes, mod edges | | simple-java/ | Java class/method nodes, import edges | | simple-ruby/