sparda-mcp 0.13.3 β†’ 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,39 +6,115 @@
6
6
 
7
7
  <br/>
8
8
 
9
- > πŸ‡«πŸ‡· **FranΓ§ais** : Pour comprendre SPARDA en 10 minutes (douleur, architecture, vision), lisez le document du fondateur : [SPARDA-EXPLIQUE.md](docs/SPARDA-EXPLIQUE.md).
9
+ <div align="center">
10
+
11
+ ## **AI writes. SPARDA proves.**
12
+
13
+ </div>
14
+
15
+ AI made writing code free. It made *trusting* code the bottleneck. Your agents open
16
+ pull requests faster than any human can truly review them, and the industry's answer
17
+ is to have another LLM skim the diff β€” an opinion grading an opinion.
18
+
19
+ SPARDA is not an opinion. It's a **behavior compiler**: it compiles your backend
20
+ (code + schema) into a deterministic behavior graph, and *proves* things against it β€”
21
+ which guard a PR removed, which invariant a deploy dropped, whether a fix broke
22
+ nothing else. Every finding is a **counterexample**, never a vibe. Zero spec to
23
+ write, zero config, zero API key, nothing leaves your machine.
24
+
25
+ One engine, four moves:
26
+
27
+ | | Command | What it proves |
28
+ |---|---|---|
29
+ | πŸ” | `sparda review` | the **behavior diff** of a PR β€” guards dropped, blast radius grown, new endpoints |
30
+ | πŸ›‘οΈ | `sparda apocalypse` | a deploy can't break any declared guard, invariant, transaction or aggregate |
31
+ | πŸͺž | `sparda mirror` | a live mock **derived from the code** β€” enforces the real state machine, can never drift |
32
+ | βͺ | `sparda timeless` / `heal` | replay a production bug deterministically; gate the fix with proof, not hope |
33
+
34
+ And because trust must extend to *runtime*, the same engine turns your app into a
35
+ safe set of MCP tools for Claude & friends β€” writes gated, failures quarantined
36
+ (see [Give your AI safe hands](#give-your-ai-safe-hands-the-mcp-layer)).
37
+
38
+ ## Review every PR's *behavior* β€” one file, zero config
10
39
 
11
- ---
40
+ Every code-review tool diffs your **text**. None diff your **behavior**. SPARDA
41
+ compiles the PR's base branch and your changes to the behavior graph and comments the
42
+ difference β€” as one sticky comment that updates on every push:
12
43
 
13
- **A compiler for backend behavior. The LLVM of web applications.**
44
+ <div align="center">
45
+ <img src="assets/pr-review-demo.svg" alt="SPARDA review bot commenting the behavior diff on a pull request: NOT PROVEN β€” GUARD_REMOVED on POST /pay, BLAST_RADIUS_GREW on POST /transfer, new endpoint POST /refund" width="740" />
46
+ </div>
14
47
 
15
- For twenty years software communicated through APIs. Then AI agents arrived, and the industry's answer was to expose more endpoints (MCP). But an agent doesn't *understand* an application from a list of disconnected tools β€” and neither can a linter, a debugger, or a deploy gate reason about a codebase they only read line by line.
48
+ <br/>
16
49
 
17
- SPARDA compiles your backend β€” routes, database queries, state mutations, permissions, side-effects β€” into one language-agnostic, mathematical graph: the **Unified Behavior Graph (UBG)**, serialized as `.sparda/ubg.json` under the **SBIR** specification ([SPARDA Behavior IR](docs/SBIR_SPEC_V1.1.md)). Compile once; then every tool is a simple pass over that graph.
50
+ Drop this one file into `.github/workflows/sparda-review.yml` β€” no key, no account,
51
+ no spec to write:
52
+
53
+ ```yaml
54
+ name: SPARDA behavior review
55
+ on: pull_request
56
+ permissions:
57
+ contents: read
58
+ pull-requests: write
59
+ jobs:
60
+ review:
61
+ runs-on: ubuntu-latest
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+ with: { fetch-depth: 0 }
65
+ - uses: zyx77550/sparda@main
66
+ with:
67
+ mode: review # comment-only by default β€” never blocks a merge
68
+ # fail-on-severity: high # uncomment to also gate the check
69
+ ```
18
70
 
19
- **What the graph unlocks β€” 100% local, deterministic, zero runtime dependencies, zero API key:**
71
+ Every finding is a **counterexample from the code + schema**, not a pattern-match β€” so
72
+ no false-positive noise to train your team to ignore. Same engine, as a hard CI gate:
73
+ `mode: apocalypse` (the default) fails the job on any critical/high and can upload
74
+ SARIF to the Security tab.
20
75
 
21
- | Command | What it does |
22
- |---|---|
23
- | **`ubg`** | Compile the codebase to its behavior graph (Express Β· FastAPI Β· Next.js natively; **any** stack via OpenAPI) |
24
- | **`apocalypse`** | *Prove the deploy* β€” no guard, invariant, transaction or aggregate boundary can be broken (SARIF + CI gate) |
25
- | **`timeless`** | *Time-travel* β€” record a production request, replay it byte-identically, export the bug as a test |
26
- | **`heal`** | *Self-heal, proven* β€” bug β†’ fix β†’ the machine proves the fix is correct and breaks nothing |
27
- | **`mirror`** | *Execute the graph* β€” serve the compiled behavior over HTTP with no framework and no source |
28
- | **`openapi`** | *Emit the standard* β€” produce an OpenAPI 3.1 spec from the graph |
29
- | **`verify`** | *Prove the compiler's own laws* (determinism, soundness, round-trip) on your app |
30
- | **`init` / `dev`** | Expose the graph to AI clients as a live MCP server (+ Twin, Immune, Evolution runtime layer) |
76
+ ## Prove the deploy
31
77
 
32
78
  ```bash
33
- npx sparda-mcp ubg # compile your backend β†’ .sparda/ubg.json
34
- npx sparda-mcp apocalypse # prove the current tree is safe to deploy
79
+ npx sparda-mcp apocalypse # PROVEN, RISKY, or NOT PROVEN β€” with counterexamples
80
+ npx sparda-mcp apocalypse --sarif # findings land in GitHub's Security tab
35
81
  ```
36
82
 
37
- No cloud account. No server to host. Exposing raw APIs to AI is the old way β€” SPARDA compiles the whole system's behavior, then proves, replays, heals, and serves it.
83
+ Five proof obligations discharged over the compiled graph β€” unguarded mutations,
84
+ unvalidated constrained writes, non-atomic aggregate writes, irreversible external
85
+ calls, aggregate bypasses β€” plus a diff against your saved baseline: no entrypoint
86
+ silently removed, no guard dropped, no blast radius grown. Exit 1 gates the pipeline.
87
+
88
+ ## A mock that can never lie
89
+
90
+ ```bash
91
+ npx sparda-mcp mirror # the graph IS the server β€” no framework, no source
92
+ ```
38
93
 
39
- **Nomenclature:** **SBIR** is the specification (the format, like "JSON"); **UBG** is the compiled graph itself (the artifact, `ubg.json`). The MCP server is one *output* of the graph, not the product.
94
+ The mirror serves your compiled behavior over HTTP: guards actually deny (401),
95
+ responses come out typed, and the **inferred state machine is enforced** β€” `POST
96
+ /orders` seeds `pending`, paying it moves it to `paid`, paying it *again* is refused
97
+ `409`. Hand-written mocks drift; this one is derived from your code + schema, so it's
98
+ synchronized by construction. Front-ends develop against backends that aren't
99
+ deployed β€” or written β€” yet.
40
100
 
41
- ## Quickstart
101
+ ## Give your AI safe hands (the MCP layer)
102
+
103
+ Your AI can write code. It still can't *operate* your app β€” and giving it raw access
104
+ usually means days of glue code and one prayer per `DELETE`. SPARDA deletes that work:
105
+
106
+ ```bash
107
+ npx sparda-mcp init # scan your Express/FastAPI/Next.js app, inject the MCP router β€” 3 minutes
108
+ npx sparda-mcp dev # connect Claude Desktop / Claude Code. Done.
109
+ ```
110
+
111
+ No OpenAPI spec. No account. No API key. No server to host. And the same trust rules
112
+ apply at runtime: **writes are disabled by default**, an enabled write needs an
113
+ explicit human confirmation (two-phase, single-use token), and every write is followed
114
+ by a proof-after-write read-back.
115
+
116
+ <details>
117
+ <summary><b>Quickstart β€” three steps</b></summary>
42
118
 
43
119
  1. **Scan + inject** β€” run once, from your app's directory:
44
120
  ```bash
@@ -68,130 +144,24 @@ No cloud account. No server to host. Exposing raw APIs to AI is the old way β€”
68
144
  Claude Code connects to the same bridge. That's it β€” your running app is now a set
69
145
  of MCP tools your AI can call.
70
146
 
147
+ </details>
148
+
71
149
  ## Try the Standalone Demo
72
150
 
73
151
  To see SPARDA in action instantly without modifying your codebase:
74
152
  ```bash
75
153
  npx sparda-mcp demo
76
154
  ```
77
- This runs the entire MCP lifecycle (detect β†’ parse β†’ generate β†’ inject β†’ remove) on a bundled demo app in a temporary folder, in about 10 seconds. For the compiler itself, run `npx sparda-mcp ubg` then `apocalypse` on any Express/FastAPI app.
155
+ This runs the entire lifecycle (detect β†’ parse β†’ generate β†’ inject β†’ remove) on a bundled demo app in a temporary folder, illustrating all six guarantees in 10 seconds.
78
156
 
79
157
  ## Black Box Report
80
158
 
81
159
  SPARDA is designed as a local organism. To see what it remembers and how much compute it has recycled:
82
160
  ```bash
83
- npx sparda-mcp report
84
- ```
85
- This prints a terminal dashboard aggregating your exposed tools, write opt-ins, proof journal decisions, and crystallized composite tools.
86
-
87
- To write a self-contained, offline HTML dashboard at `.sparda/report.html`, append the `--html` flag:
88
- ```bash
89
- npx sparda-mcp report --html
90
- ```
91
-
92
- To output raw JSON for integration:
93
- ```bash
94
- npx sparda-mcp report --json
95
- ```
96
-
97
- ## Deployment Proof: Apocalypse
98
-
99
- SPARDA's Behavior Graph is a formal model of your system. Instead of waiting for runtime failures or relying on static analysis vibes, you can statically prove the safety of your backend before any deployment:
100
- ```bash
101
- npx sparda-mcp apocalypse
102
- ```
103
- This command reads the compiled `.sparda/ubg.json` (with zero source code parsing at runtime) and discharges five static correctness obligations:
104
- * **Unguarded Mutation (Critical)**: Flags any mutation path that does not cross a security `guard`.
105
- * **Non-Atomic Aggregate Write (High)**: Flags when an API writes to multiple tables of the same Consistency Domain (Aggregate) outside a single transaction scope.
106
- * **Unvalidated Constrained Write (Medium)**: Flags writes into columns with declared invariants (CHECK, NOT NULL, UNIQUE β€” parsed from your `.sql` DDL **or `schema.prisma`**, Prisma enums included) without prior validation (Zod/Pydantic).
107
- * **Irreversible Observable Effect (High)**: Flags out-of-process actions (like Stripe charges) that happen alongside state writes without a structural compensation path (like a catch-refund).
108
- * **Aggregate Member Bypass (Info)**: Flags mutating a member table directly without routing through the aggregate root.
109
-
110
- To save your current graph as a safe baseline:
111
- ```bash
112
- npx sparda-mcp apocalypse --save-baseline
161
+ npx sparda-mcp report # terminal dashboard
162
+ npx sparda-mcp report --html # self-contained offline dashboard at .sparda/report.html
163
+ npx sparda-mcp report --json # raw JSON for integration
113
164
  ```
114
- Subsequent runs will diff the candidate graph against this baseline to detect regression vectors:
115
- * Deletion of any security `guard` (Critical).
116
- * Deletion of a database SQL invariant (High).
117
- * API blast radius expansion (Medium).
118
-
119
- If any Critical or High finding is found, `apocalypse` exits with a non-zero code to block your CI pipeline.
120
-
121
- **One step in your workflow β€” findings land in the GitHub Security tab (SARIF):**
122
- ```yaml
123
- - uses: zyx77550/sparda@main
124
- with:
125
- sarif: 'true'
126
- ```
127
-
128
- ## Time Travel: Timeless
129
-
130
- Every production request is deterministic between its effects β€” the compiler knows exactly where the nondeterminism lives (db, http, clock, random, uuid: the effect nodes of the graph). Timeless records only those points (a few KB per request) and replays the request **byte-identically** against your current code, with the database, webhooks and clock virtualized from the recording:
131
-
132
- ```bash
133
- npx sparda-mcp timeless # list recorded flights
134
- npx sparda-mcp timeless replay <id> # re-fly it β€” byte-identical or loud divergence
135
- npx sparda-mcp timeless export <id> # the production bug is now a vitest test
136
- ```
137
-
138
- Recording is two lines in your app (ESM), with deterministic sampling and GDPR redaction built in:
139
- ```js
140
- import { getFlightBox } from 'sparda-mcp/src/flight/box.js';
141
- const box = getFlightBox(); box.arm();
142
- app.use(box.middleware({ sample: 100 })); // 1 request in 100; passwords/tokens redacted by default
143
- const db = box.wrapClient(pgPool); // your query client, tapped
144
- ```
145
-
146
- The closed loop nobody else has: **production bug β†’ recorded flight β†’ failing test β†’ AI writes the fix β†’ `apocalypse` proves the fix breaks no guard, invariant or transaction β†’ deploy.** Replay is per-request (concurrent-race capture is out of scope for v1 β€” stated, not hidden).
147
-
148
- ## Self-Healing, Proven: `sparda heal`
149
-
150
- The loop above, as **one gesture** β€” and the machine judges the fix, whoever wrote it:
151
-
152
- ```bash
153
- npx sparda-mcp heal <flightId> # diagnose + write the fix brief
154
- # ...apply the fix (a human, or --agent "your-ai-cli")...
155
- npx sparda-mcp heal <flightId> --check --expect '{"status":404}'
156
- ```
157
-
158
- The brief is built from the graph itself β€” it hands the fixer the handler's `file:line`, the capabilities the fix must not grow, and the guards it must not remove. Then the **gate** β€” the actual product β€” proves the fix on three axes at once:
159
-
160
- 1. **Behavior** β€” lenient replay of the recorded flight (same deterministic inputs) now produces the *expected* response, not the recorded bug. The fix may reformulate a query (the tap is relabeled, allowed); it may **not** change the effect order or kinds.
161
- 2. **Compiler laws** β€” `verify` still passes: the graph is still sound and deterministic.
162
- 3. **No regression** β€” `apocalypse` diff against the frozen pre-fix graph: zero new critical/high findings, no guard removed, no blast radius grown.
163
-
164
- ```
165
- βœ“ HEALED & PROVEN β€” same recorded inputs, correct output, zero law broken, zero protection lost. Ship it.
166
- ```
167
-
168
- The gate is honest in both directions: an unfixed bug, or a "fix" that silently drops a guard, keeps it **closed** (exit 1). This is the difference between an AI that writes plausible code and a system that *proves* the code is correct β€” the trust layer the agent era is missing.
169
-
170
- ## Any Backend On Earth: OpenAPI Lowering
171
-
172
- SPARDA parses Express, FastAPI and Next.js natively β€” and **every other stack through the format the industry already agreed on**. Go, Java, Rails, Laravel, .NET: if it has an OpenAPI spec, it compiles.
173
-
174
- ```bash
175
- npx sparda-mcp ubg --openapi openapi.json
176
- ```
177
-
178
- Security schemes become gating `guard` nodes, response schemas become typed returns, declared request bodies count as validated input. Pair the spec with your `.sql` or `schema.prisma` files and the full state layer β€” invariants, aggregates, state machines β€” fills in from declared truth. (JSON specs in v1; we refuse to half-parse YAML with zero dependencies.)
179
-
180
- ## The Mirror VM: delete the framework, the app still answers
181
-
182
- The graph is not a diagram β€” it executes:
183
-
184
- ```bash
185
- npx sparda-mcp mirror
186
- ```
187
-
188
- ```
189
- MIRROR β€” the graph is serving. 3 entrypoint(s) on http://127.0.0.1:4477
190
- GET /orders/{orderId} β†’ {amount, id, status}
191
- POST /orders πŸ”’ bearerAuth β†’ {amount, id, status}
192
- ```
193
-
194
- No Express. No FastAPI. No source code β€” just `ubg.json` answering HTTP: guards actually deny (401), responses render the compiled return schemas, unknown paths 404 with the full route table. Front-end teams develop against backends that aren't deployed yet β€” or aren't written yet (point `mirror` at an OpenAPI spec). Every response carries `x-sparda-mirror: true`; the mirror serves declared behavior, it never invents business values.
195
165
 
196
166
  To undo everything: **`npx sparda-mcp remove`** restores your code byte-for-byte.
197
167
 
@@ -203,10 +173,10 @@ To undo everything: **`npx sparda-mcp remove`** restores your code byte-for-byte
203
173
 
204
174
  <br/>
205
175
 
206
- 1. **Three minutes, one command.** AST scan, router generation, reversible injection β€” no config.
207
- 2. **Try it for free, leave for free.** `npx sparda-mcp remove` restores your code **byte-for-byte** (tested on JS, TS, Python, even Windows CRLF files). No trace, no lock-in.
208
- 3. **The AI cannot write until you say so.** Every POST/PUT/DELETE is disabled by default; you enable per tool, and your choice survives every re-run.
209
- 4. **Your app defends itself.** A route failing 3 times in a row is quarantined β€” the AI can't hammer your broken production. Latency anomalies are flagged. Zero LLM needed.
176
+ 1. **Proof, not opinion.** Every review/apocalypse finding is a counterexample derived from your code + schema β€” deterministic, byte-identical run after run, machine after machine.
177
+ 2. **Three minutes, one command.** AST scan, router generation, reversible injection β€” no config.
178
+ 3. **Try it for free, leave for free.** `npx sparda-mcp remove` restores your code **byte-for-byte** (tested on JS, TS, Python, even Windows CRLF files). No trace, no lock-in.
179
+ 4. **The AI cannot write until you say so.** Every POST/PUT/DELETE is disabled by default; you enable per tool, and your choice survives every re-run.
210
180
  5. **Nothing leaves your machine.** No telemetry to us, no cloud, local key auth, 4 exact-pinned dependencies.
211
181
  6. **What it learns is never lost.** Diagnoses, descriptions, settings β€” versioned with your git, surviving every re-init.
212
182
 
@@ -214,23 +184,14 @@ What we *don't* promise: the honest limits in [docs/SECURITY.md](./docs/SECURITY
214
184
 
215
185
  ## How it works
216
186
 
217
- 1. `npx sparda-mcp init` parses your codebase (AST), extracts every route, and injects a tiny marked router (`/mcp`) into your app β€” fully reversible with `npx sparda-mcp remove`.
218
- 2. Tool calls run **inside your live app process** β€” warm DB pools, real auth chain, real data. SPARDA adds no infrastructure: compute comes from your host process, intelligence from your AI client's own model (MCP sampling), storage from `sparda.json` + git.
219
- 3. Write tools (POST/PUT/DELETE) are **disabled by default**. You opt in per tool in `sparda.json` β€” your choices survive re-runs.
187
+ 1. **The compiler.** `sparda ubg` (run implicitly by `review`/`apocalypse`/`mirror`) parses your codebase and SQL/Prisma schema (AST β€” 100% local, zero LLM) into a deterministic behavior graph: entrypoints, guards, effects, state, invariants, state machines. `sparda verify` proves the compiler's own laws (determinism, soundness, round-trip) on your input.
188
+ 2. **The proofs.** `review` and `apocalypse` discharge proof obligations over that graph; `mirror` executes it; `timeless` records/replays real requests against it.
189
+ 3. **The MCP layer.** `init` injects a tiny marked router (`/mcp`) into your app β€” fully reversible with `remove`. Tool calls run **inside your live app process** β€” warm DB pools, real auth chain, real data. Zero infrastructure: compute from your host process, intelligence from your AI client's own model (MCP sampling), storage from `sparda.json` + git.
220
190
  4. Suspicious docstrings are sanitized before they ever reach the AI (prompt-injection defense).
221
- 5. `npx sparda-mcp doctor --app` audits your codebase for drift: it detects stale tools (IA seeing ghosts), unsynced routes, schema drift via fingerprints, and zombie configurations. High severity issues trigger a non-zero exit code for your CI pipeline.
222
- 6. `npx sparda-mcp seed export/import` lets you package and share your app's "genome" (semantic memory, workflows, antibodies) securely, transferring immune memory between environments or across similar stacks with zero data leak.
223
- 7. `npx sparda-mcp twin` starts a safe, simulated mock server of your backend on the original port. It serves GET calls from learned exemplars (observed response shapes & mock data) and returns simulated 202 writes without ever touching your real database or production APIs. Learn exemplars by running `npx sparda-mcp twin --learn`.
224
- 8. `npx sparda-mcp grammar` maps the graph of valid sequences of tool calls (observed circuits and candidate hypotheses) to prevent LLM hallucination of routes.
225
- 9. `npx sparda-mcp evolve` mutates candidate chains and tests them against the twin in-memory, promoting successful chains to evolved workflow suggestions.
226
191
 
227
- ## What SPARDA gives your AI
192
+ ## The living organism β€” what runtime trust looks like
228
193
 
229
- ### Operate, not just read
230
- Every route becomes a tool that runs against your live process β€” real auth, real data,
231
- warm connections. One call to **`sparda_get_context`** hands the AI the whole living
232
- picture: enabled tools, suggested workflows, runtime telemetry, quarantine state, and
233
- immune memory β€” so every session resumes where the last one stopped.
194
+ The proof gate covers what AI *writes*. These organs cover what AI *does*, live:
234
195
 
235
196
  ### Write-safety: the AI can't write until you say so
236
197
  - Writes (POST/PUT/DELETE) ship **disabled**. Enable them per tool in `sparda.json`; your choice survives every re-init.
@@ -262,9 +223,10 @@ step's real response. Write routes are never absorbed β€” their per-call confirm
262
223
  always stands.
263
224
 
264
225
  ### Living context & telemetry
265
- `GET /mcp/stats` (per-tool calls/errors, tool "purity", quarantine state) and
266
- `GET /mcp/events` (errors, latency anomalies, cached diagnoses) expose exactly what
267
- your app is doing β€” surfaced to the AI as live notifications.
226
+ One call to **`sparda_get_context`** hands the AI the whole living picture: enabled
227
+ tools, suggested workflows, runtime telemetry, quarantine state, and immune memory β€”
228
+ so every session resumes where the last one stopped. `GET /mcp/stats` and
229
+ `GET /mcp/events` expose the same live picture over HTTP.
268
230
 
269
231
  ## Built for AI clients: the bundled Skill
270
232
  SPARDA ships with an Agent Skill ([`SKILL.md`](./SKILL.md)) that teaches any compatible
@@ -279,10 +241,10 @@ runtime, so the guidance never goes stale.
279
241
  - **Next.js App Router (13/14/15)** β€” file-based injection. Since Next.js uses file-system routing, SPARDA simply creates a catch-all route handler under `app/mcp/[...sparda]/route.js`. **Nothing in your existing codebase's code is touched**; running `remove` simply deletes the generated file.
280
242
  - **Express 4/5** (JS/TS, ESM/CJS) β€” AST-based router injection.
281
243
  - **FastAPI** (Python >= 3.9) β€” AST-based router injection.
244
+ - **Any backend with an OpenAPI spec** β€” `--openapi api.json` lowers the spec into the same behavior graph, so `review`, `apocalypse`, `mirror` and `openapi` work on Go, Rails, Java, .NET… without a parser.
282
245
 
283
246
  ## Security posture (honest)
284
247
  - 4 runtime dependencies, exact-pinned.
285
- - **Dynamic Local Key Resolution.** The generated router contains no baked secrets. It resolves authorization keys at runtime from the `SPARDA_LOCAL_KEY` environment variable or the local gitignored `.sparda/key` file, and fails closed (503) when neither is found. For custom production or staging setups, you can override this behavior by exposing `SPARDA_LOCAL_KEY` in your environment.
286
248
  - Local key on every router call; self-reference loop protection; 30s timeouts; 8 KB output truncation.
287
249
  - AST-positioned injection with backup and post-injection re-parse; `npx sparda-mcp remove` leaves a clean git diff.
288
250
  - Persistence is **value-free**: SPARDA records structure (tool names, field names, fingerprints), never your payloads.
package/SKILL.md CHANGED
@@ -1,32 +1,42 @@
1
1
  ---
2
2
  name: sparda-mcp
3
3
  description: >-
4
- Drive a SPARDA compiled Behavior Runtime to its full potential. Use this whenever
5
- you are connected to a backend running the SPARDA Runtime (compiled into a Unified
6
- Behavior Graph - UBG) β€” recognizable by the tools `sparda_get_context`, `sparda_info`,
7
- `sparda_confirm`, or composite tools. It teaches the graph-context-first workflow,
8
- how to exploit the response-recycling flywheel, the circuit-breaker, crystallized
9
- circuits, offline Twin simulations, and the two-phase confirm protocol for writes.
4
+ Drive a SPARDA-generated MCP server to its full potential. Use this whenever
5
+ you are connected to an MCP server built by SPARDA (sparda-mcp) β€” recognizable
6
+ by the tools `sparda_get_context`, `sparda_info`, `sparda_confirm`, or composite
7
+ tools labelled "[Labs circuit]". It teaches the call-context-first workflow, how
8
+ to exploit the response-recycling flywheel, the circuit-breaker, crystallized
9
+ circuits and adaptive immunity, and the mandatory two-phase confirm protocol for
10
+ write tools. Reach for it before calling raw endpoints, before any write, or when
11
+ a tool returns 202 (awaiting confirmation) or 503 (quarantined).
10
12
  ---
11
13
 
12
- # Driving a SPARDA Behavior Runtime
14
+ # Driving a SPARDA MCP server
13
15
 
14
- A SPARDA server is driven by a compiled **Unified Behavior Graph (UBG)** β€” the graph SPARDA's compiler produces from the host application's states, transitions, permissions, and side-effects, serialized under the **SBIR** specification. Instead of exposing raw, disconnected endpoints, SPARDA compiles the app into a deterministic behavioral model. The local **SPARDA Runtime** dynamically executes this graph inside the live host process, powering the MCP interface, the Twin simulation clone, and the Immune system offline.
15
-
16
- > This skill covers the **runtime** (driving a live MCP server). The same graph also powers dev-time compiler commands you run in the app's repo β€” `sparda ubg` (compile), `apocalypse` (prove the deploy), `timeless` (record/replay a request), `heal` (prove a fix), `mirror` (serve the graph), `verify` (prove the compiler's laws). Those are CLI, not MCP tools; see the project README.
16
+ A SPARDA server is **not** a flat list of HTTP endpoints. SPARDA injected a live
17
+ `/mcp` router *inside a real running app*, so its tools are that app's actual
18
+ routes β€” wrapped in an intelligence layer that makes repeated use **cheaper** (it
19
+ recycles stable answers from memory) and **safer** (it quarantines failing tools
20
+ and gates writes behind human confirmation). This is the runtime half of SPARDA's
21
+ trust layer β€” "AI writes. SPARDA proves." β€” the same engine that proves PRs and
22
+ deploys (`sparda review` / `apocalypse`) also guards what you *do* to the live app.
23
+ Used naively it's just an API. Used well, it gets faster and safer the more you
24
+ call it. This skill is how to use it well.
17
25
 
18
26
  ## Rule 0 β€” call `sparda_get_context` first, every session
19
27
 
20
- Before anything else, call **`sparda_get_context`** (no params). It returns the *live* state of the SPARDA Behavior Graph:
28
+ Before anything else, call **`sparda_get_context`** (no params). It returns the
29
+ *live* picture, so you never guess the surface:
21
30
 
22
- - the active routes/tools, workflows, and type-propagated schemas;
23
- - `runtime` β€” current stats (calls, errors, quarantine states, Twin mode active);
24
- - the last ~20 **events** (errors, latency anomalies, immune alerts);
25
- - **immune memory** (cached antibodies and error diagnoses);
26
- - **recycling** metrics (flywheel memory hit rates);
27
- - a `behavior` snapshot of stable variables.
31
+ - the enabled tools + their descriptions, and SPARDA's suggested **workflows**;
32
+ - `runtime` β€” current `/mcp/stats` (per-tool call/error counts, tool "purity",
33
+ quarantine state);
34
+ - the last ~20 **events** (errors, latency anomalies, immune diagnoses);
35
+ - **immune memory** (known failure signatures + cached fixes);
36
+ - **recycling** stats (how many calls were served from memory);
37
+ - a `behavior` snapshot (which response fields are stable).
28
38
 
29
- Read it to orient yourself inside the graph. `sparda_info` gives a lighter summary of counts.
39
+ Read it before acting. `sparda_info` gives a lighter summary if you only need counts.
30
40
 
31
41
  ## The tools you'll see
32
42
 
@@ -76,16 +86,6 @@ adapt β€” don't blindly retry the same call.
76
86
  **5. Latency anomalies.** A call far slower than a tool's own baseline surfaces as
77
87
  an `immune` event in `/mcp/events`. Treat it as a hint to back off or warn the user.
78
88
 
79
- **6. Twin Simulation Mode β€” practice safely on a clone.**
80
- When `/mcp/stats` or `sparda_get_context.runtime` contains `"twin": true`, you are connected to a safe, in-memory mock clone of the application.
81
- - All GET reads return learned exemplars (observed response shapes and mock values).
82
- - All write tools return simulated `202` echoes but do not write to database or external APIs.
83
- - Use this twin mode to practice multi-step workflows, debug tool sequences, and test your plans without touching the live production backend.
84
-
85
- **7. Grammar & Evolution β€” discover optimal workflows.**
86
- - You can query or contribute to the app's grammar (`.sparda/grammar.json`). The grammar maps valid sequences of tool calls (edges).
87
- - Running `sparda evolve` mutates and runs candidate chains against the twin. The successful evolved sequences are suggested as mid-session workflows.
88
-
89
89
  ## Writing safely β€” the mandatory two-phase protocol
90
90
 
91
91
  Writes are **disabled by default**. The protocol is not optional:
@@ -138,15 +138,6 @@ Writes are **disabled by default**. The protocol is not optional:
138
138
  - **General health** β†’ `sparda doctor` checks Node version, framework detection,
139
139
  manifest validity, the semantic/immune cache, host reachability, and quarantine;
140
140
  it exits non-zero so it can gate CI.
141
- - **Formal Deployment Proof** β†’ `sparda apocalypse` reads the compiled graph (`ubg.json`) and proves five correctness obligations: catches unguarded mutations, non-atomic aggregate writes, unvalidated writes to constrained tables, uncompensated observable effects, and aggregate root bypasses. Run `sparda apocalypse --save-baseline` to store the reference graph; subsequent runs diff against the baseline to catch dropped guards, dropped SQL invariants, or grown blast radiuses.
142
- - **OpenAPI Ingestion** β†’ Run `sparda ubg --openapi <openapi_spec.json>` to compile any non-JS/Python backend (Go, Java, Rails, Laravel, .NET) into a Unified Behavior Graph by mapping security schemes into guards and request/response structures. (JSON specs only β€” convert YAML once with `npx -y js-yaml spec.yaml > spec.json`.)
143
- - **Executing the Graph (No code mock)** β†’ Run `sparda mirror` to host a mock HTTP simulation server directly from `ubg.json` without any backend code. Enforces authentication guards, returns typed responses, and acts as a contract sandbox.
144
- - **Exporting OpenAPI 3.1 Spec** β†’ Run `sparda openapi` to generate a valid, deterministic OpenAPI 3.1 spec dynamically from the compiled behavior graph.
145
- - **Self-Verification** β†’ Run `sparda verify` to test the compiler's own invariants (byte-determinism, soundness, and spec round-trip) to guarantee trust.
146
- - **Time-Travel Debugging** β†’ `sparda timeless` records a production request's nondeterminism (db, http, clock, random, uuid) and replays it byte-identically against current code. `sparda timeless replay <id>` re-flies it; `sparda timeless export <id>` turns the bug into a vitest test. Recording is opt-in in the app (deterministic sampling + GDPR redaction built in).
147
- - **Self-Healing, Proven** β†’ `sparda heal <id>` builds a fix brief from the graph, then `--check --expect '{"status":200}'` gates a candidate fix on three axes at once: the recorded flight now returns the expected response (not the bug), `verify` still passes, and `apocalypse` finds no new critical/high and no removed guard. The gate is honest both ways β€” an unfixed bug keeps it closed (exit 1).
148
- - **Clone learning / Transfer sΓ©mantique** β†’ Use `sparda seed export` to package your app's descriptions, workflows, and antibodies. Then `sparda seed import --germinate` in another clone to import the structure and germinate simulated twin instances.
149
- - **Learn exemplars** β†’ Start your live app and run `sparda twin --learn` to fetch actual response data and construct `.sparda/twin.json` locally.
150
141
 
151
142
  ---
152
143
  *This skill ships with `sparda-mcp` and is regenerated from SPARDA's capability
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparda-mcp",
3
- "version": "0.13.3",
3
+ "version": "0.14.1",
4
4
  "mcpName": "io.github.zyx77550/sparda-mcp",
5
5
  "description": "Compile backends to behavior graphs. Statically prove security, simulate APIs, and replay bugs.",
6
6
  "type": "module",
@@ -16,7 +16,7 @@ import { atomicWriteFileSync as atomicWrite } from '../server/persistence.js';
16
16
  const ICONS = { critical: 'βœ—', high: 'βœ—', medium: '⚠', info: 'Β·' };
17
17
 
18
18
  export async function runApocalypse(opts) {
19
- const { graph } = compileUBG(opts.cwd, { write: false });
19
+ const { graph, report } = compileUBG(opts.cwd, { write: false });
20
20
  const canonical = canonicalizeGraph(graph);
21
21
  const baselinePath = path.join(opts.cwd, '.sparda', 'ubg.baseline.json');
22
22
 
@@ -42,7 +42,7 @@ export async function runApocalypse(opts) {
42
42
  }
43
43
 
44
44
  const findings = [...staticFindings, ...diffFindings];
45
- const verdict = verdictOf(findings);
45
+ const verdict = verdictOf(findings, canonical);
46
46
 
47
47
  if (opts.sarif) {
48
48
  const sarifPath = path.join(opts.cwd, '.sparda', 'apocalypse.sarif');
@@ -64,7 +64,21 @@ export async function runApocalypse(opts) {
64
64
  console.log(` ${ICONS[f.severity]} [${f.severity}] ${f.rule} β€” ${f.message}`);
65
65
  if (opts.verbose) for (const ev of f.evidence) console.log(` evidence: ${ev}`);
66
66
  }
67
- if (verdict.clean) {
67
+ if (!verdict.provable) {
68
+ console.log(
69
+ `βœ— NO PROOF β€” 0 routes reached. SPARDA could not see this app's surface (a parser-coverage gap, not a clean bill of health); an empty graph proves nothing. This is NOT a pass β€” run with --verbose to see what was skipped.`,
70
+ );
71
+ if (opts.verbose) {
72
+ console.log(` detected: ${report.framework} Β· entry ${report.entry}`);
73
+ if (report.skipped?.length)
74
+ for (const s of report.skipped)
75
+ console.log(` skipped: ${s.reason}${s.file ? ` (${s.file})` : ''}`);
76
+ else
77
+ console.log(
78
+ ` no route call sites reached β€” routes are likely registered indirectly (a loader / DI pattern the static walk can't follow).`,
79
+ );
80
+ }
81
+ } else if (verdict.clean) {
68
82
  console.log(
69
83
  `βœ“ PROVEN β€” ${obligations} obligation(s) discharged, zero violations. No declared guard, invariant, transaction or aggregate boundary can be broken by this tree.`,
70
84
  );
@@ -29,14 +29,27 @@ export async function runMirror(opts) {
29
29
  server.listen(port, '127.0.0.1', resolve);
30
30
  });
31
31
 
32
+ const stateful = routes.filter((r) => r.transitions.length || r.reflect);
32
33
  console.log(
33
- `MIRROR β€” the graph is serving. ${routes.length} entrypoint(s) on http://127.0.0.1:${port}`,
34
+ `MIRROR β€” the graph is serving. ${routes.length} entrypoint(s) on http://127.0.0.1:${port}` +
35
+ (stateful.length ? ` Β· ${stateful.length} live the inferred lifecycle` : ''),
34
36
  );
35
37
  for (const r of routes) {
36
- console.log(
37
- ` ${r.method.toUpperCase().padEnd(6)} ${r.path}${r.guarded ? ' πŸ”’ ' + r.guards.join(',') : ''}${r.returns ? ' β†’ {' + Object.keys(r.returns).join(', ') + '}' : ''}`,
38
- );
38
+ const guard = r.guarded ? ' πŸ”’ ' + r.guards.join(',') : '';
39
+ const shape = r.returns ? ' β†’ {' + Object.keys(r.returns).join(', ') + '}' : '';
40
+ const life = r.transitions.length
41
+ ? ' ⟳ ' + r.transitions.map((t) => `${t.field}:${t.from}β†’${t.to}`).join(', ')
42
+ : r.reflect
43
+ ? ` ↩ reflects ${r.reflect.field}`
44
+ : '';
45
+ console.log(` ${r.method.toUpperCase().padEnd(6)} ${r.path}${guard}${shape}${life}`);
39
46
  }
40
- console.log(' (every response carries x-sparda-mirror: true β€” Ctrl+C to stop)');
47
+ console.log(
48
+ ' (every response carries x-sparda-mirror: true' +
49
+ (stateful.length
50
+ ? '; ⟳ routes enforce the state machine (409 on illegal moves)'
51
+ : '') +
52
+ ' β€” Ctrl+C to stop)',
53
+ );
41
54
  return { server, routes, port };
42
55
  }
@@ -54,6 +54,24 @@ export async function runRemove(opts) {
54
54
  `βœ— Could not safely remove from ${r.file} β€” restore from .sparda/backup/`,
55
55
  );
56
56
  }
57
+
58
+ // Hard rule #4 safety: if any injected file could NOT be cleanly reverted, STOP before
59
+ // any destructive cleanup. Deleting `.sparda/` here would erase the very `.sparda/backup/`
60
+ // we just told the operator to restore from β€” so nothing is removed until the tree is
61
+ // known-clean. The manifest and backups stay put for a manual (or retried) recovery.
62
+ const failed = results.filter((r) => !r.ok);
63
+ if (failed.length) {
64
+ console.log(
65
+ `\nβœ— ${failed.length} file(s) could not be reverted automatically. Nothing else was deleted β€”` +
66
+ ` sparda.json, generated files and .sparda/backup/ are preserved.`,
67
+ );
68
+ console.log(
69
+ ' Restore the file(s) above from .sparda/backup/, then re-run `npx sparda-mcp remove`.',
70
+ );
71
+ process.exitCode = 1;
72
+ return { removed: false, failed: failed.map((r) => r.file) };
73
+ }
74
+
57
75
  for (const f of manifest.generatedFiles ?? []) {
58
76
  const abs = path.resolve(opts.cwd, f);
59
77
  if (fs.existsSync(abs)) {
@@ -85,6 +103,7 @@ export async function runRemove(opts) {
85
103
  fs.rmSync(path.join(opts.cwd, '.sparda'), { recursive: true, force: true });
86
104
  console.log('βœ“ Deleted sparda.json and .sparda/');
87
105
  console.log('\nSPARDA removed. `git diff` should be clean.');
106
+ return { removed: true };
88
107
  }
89
108
 
90
109
  // Undo exactly what init's ensureGitignore did (recorded in the manifest),