sparda-mcp 0.13.3 β 0.14.0
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 +117 -155
- package/SKILL.md +28 -37
- package/package.json +1 -1
- package/src/commands/mirror.js +18 -5
- package/src/commands/remove.js +19 -0
- package/src/commands/review.js +206 -0
- package/src/generator/express.js +12 -18
- package/src/generator/fastapi.js +7 -18
- package/src/generator/injection.js +36 -0
- package/src/generator/nextjs.js +120 -120
- package/src/index.js +8 -0
- package/src/server/stdio.js +12 -1
- package/src/ubg/apocalypse.js +279 -0
- package/src/ubg/mirror.js +158 -10
- package/src/ubg/passes/consistency-domains.js +5 -2
- package/src/ubg/passes/state-machines.js +2 -3
- package/src/ubg/passes/state-minimization.js +3 -1
- package/src/ubg/passes/type-propagation.js +8 -3
- package/src/ubg/prisma.js +3 -1
- package/src/ubg/schema.js +0 -0
- package/src/ubg/sql.js +3 -4
- package/src/ubg/translate.js +3 -2
- package/templates/express-router.txt +7 -1
- package/templates/fastapi-router.txt +661 -661
- package/templates/nextjs-router.txt +4 -1
package/README.md
CHANGED
|
@@ -6,39 +6,115 @@
|
|
|
6
6
|
|
|
7
7
|
<br/>
|
|
8
8
|
|
|
9
|
-
>
|
|
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
|
-
|
|
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
|
-
|
|
48
|
+
<br/>
|
|
16
49
|
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
34
|
-
npx sparda-mcp apocalypse
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
|
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
|
-
|
|
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. **
|
|
207
|
-
2. **
|
|
208
|
-
3. **
|
|
209
|
-
4. **
|
|
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. `
|
|
218
|
-
2.
|
|
219
|
-
3.
|
|
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
|
-
##
|
|
192
|
+
## The living organism β what runtime trust looks like
|
|
228
193
|
|
|
229
|
-
|
|
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
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
|
5
|
-
you are connected to
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
circuits
|
|
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
|
|
14
|
+
# Driving a SPARDA MCP server
|
|
13
15
|
|
|
14
|
-
A SPARDA server is
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
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
|
|
23
|
-
- `runtime` β current stats (
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
- **
|
|
27
|
-
-
|
|
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
|
|
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
package/src/commands/mirror.js
CHANGED
|
@@ -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
|
-
|
|
37
|
-
|
|
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(
|
|
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
|
}
|
package/src/commands/remove.js
CHANGED
|
@@ -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),
|