strata
by stratalib
README.md
<div align="center">
<img src="docs/assets/banner.svg" alt="Strata — verified backend modules, composed and proven" width="620">
### Your agent writes the backend. Strata proves it runs.
An MCP server that composes verified backend modules into your codebase — reading your schema,
following your conventions, wiring them in the order Express actually requires — then writes one
command that boots the app and exercises every requirement against a live server.
<br>
[](https://www.npmjs.com/package/stratalib)
[](https://nodejs.org)
[](https://modelcontextprotocol.io)
[](LICENSE)
[](https://stratalib.com)
[](https://x.com/stratalib)
[](CHANGELOG.md)
[](docs/BENCHMARK.md)
[](docs/BENCHMARK.md)
[](docs/BENCHMARK.md)
[](docs/BENCHMARK.md)
[](docs/BENCHMARK.md)
[](#admission-gates)
</div>
<br>
```console
$ # your agent calls one tool, once
strata_use dir=./shop-api task="product list API"
capabilities=[ "cursor pagination with sorting",
"per-IP rate limiting",
"structured request logging" ]
FILES CREATED
server.js
strata/lib.js — the implementation these import from
strata/verify.js — boots the app and exercises the feature end to end
$ npm install && node strata/verify.js
PASS unit selftests — 3 passed, 0 failed
PASS server boots and answers /health
PASS correlation id honours an inbound x-request-id
PASS an authorization header is NOT written to the log
PASS a password in a request BODY is NOT written to the log
PASS a malformed body is a 4xx and leaks no stack trace to the caller
PASS /items walks pages by cursor without repeating a row
PASS a sort field that is not allowlisted is REJECTED, not honoured
PASS a burst past capacity yields 429 + Retry-After
12/12 checks passed — the delivered feature works end to end.
```
<div align="center">
<sub>Real output. Those check names are the whole idea — anyone can generate pagination,<br>
the question is whether page two repeats page one.</sub>
</div>
---
**Key capabilities**
- **Schema-aware composition** — reads Prisma, Mongoose, Drizzle, TypeORM, Sequelize or plain JS and wires modules against your real entity, fields and ID column
- **Correct middleware ordering** — logging above body parsing, rate limits above routes, error handlers last, enforced by rank rather than left to the model
- **Generated end-to-end verifier** — `strata/verify.js` boots the app on a free port and drives every requirement against it
- **Six machine-checked admission gates** — no module reaches your project without passing all of them
- **Honest declines** — refuses roughly a third of tasks, where composing costs more than writing the code
<br>
```console
$ # asked for something the library does not cover
strata_use task="slugify helper" capabilities=["convert a string to a url slug"]
No verified Strata recall covers "slugify helper". Build it from scratch the
normal way — a clean hand-written implementation is the right outcome here,
not a forced match.
```
<div align="center">
<sub>Refusing is a feature. One module is not worth the cost of reading and verifying it,<br>
and a tool that always says yes is a tool you stop trusting.</sub>
</div>
- **Local by construction** — your source and schema never leave the machine; only the task text is sent
---
## The numbers
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/savings-dark.svg">
<img src="docs/assets/savings-light.svg" alt="Same task, same model: 66% fewer tokens, 52% fewer turns, 67% less wall-clock time." width="760">
</picture>
</div>
<div align="center">
| | without Strata | **with Strata** | |
|---|---|---|---|
| **tokens** | 950,011 | **319,604** | **−66%** |
| **turns** | 31.3 | **15.0** | **−52%** |
| **wall-clock** | 190s | **63s** | **3× faster** |
| **cost** | $0.190 | **$0.077** | **−59%** |
| **checks passed** | 70.8% | **100%** | |
</div>
One backend task — a product API with pagination, per-IP rate limiting and request logging. Claude Haiku 4.5, three runs per arm, mean. **Every number is lower and the quality is higher.**
Tokens are the whole session: input, output and the cached context re-read on every turn. Across all 18 runs in this battery, **98–99% of a session's tokens are that re-read context** — output is under 2%. So output length is not the lever; turns are, and fewer turns is the same thing as fewer tokens is the same thing as less money.
---
## What the failed checks actually were
A score is easy to wave away. These are the failures themselves, re-graded from the archived trees. Every one is code that runs, answers 200-or-201, and looks finished.
### A malformed request returns your stack trace
One request with a truncated body. **Both apps answered 400 — only one of them is safe.**
<table>
<tr><th align="left" width="50%">without Strata</th><th align="left" width="50%">with Strata</th></tr>
<tr valign="top"><td>
```html
<!DOCTYPE html>
<html lang="en"><head><title>Error</title></head>
<body>
<pre>SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at parse (C:\Users\...\node_modules\body-parser
\lib\types\json.js:96:19)
at C:\Users\...\body-parser\lib\read.js:128:18
at AsyncResource.runInAsyncScope (node:async_...
```
HTML from a JSON API, the parser's internals, and **absolute paths from your server's filesystem** — handed to whoever sent the bad byte.
</td><td>
```json
{
"error": "malformed JSON in request body",
"details": [
{ "field": "body",
"message": "could not be parsed as JSON" }
]
}
```
The same 400, in the same envelope as every other error, telling the caller what to fix and nothing else.
</td></tr>
</table>
**Failed in 6 of 6 unaided runs, across both tasks. Passed in 6 of 6 with Strata.** The grader records it as `LEAKS STACK TRACE`; nothing in the session's own output mentions it.
### A retried order with a different body was accepted anyway
```
POST /orders Idempotency-Key: k-1 {"items":[ A ]} → 201 Created
POST /orders Idempotency-Key: k-1 {"items":[ B ]} → 200 OK ← order A returned
```
That is the subtle half of idempotency, and the half a naive implementation misses entirely. The client asked for a **different** order and was told its request succeeded. Nothing errors, nothing logs. Order B simply never exists, and the caller holds a 200 saying it does. The correct answer is 409 or 422.
**Failed in 3 of 3 unaided runs. Passed in 3 of 3 with Strata.**
### The API ignored the page size it was asked for
```
GET /products?limit=5 → 200 OK, 10 items
```
Pagination that returns whatever it likes. Nothing errors, nothing logs, and the bug reaches whoever consumes that endpoint. One unaided run in three.
### The database schema was edited, unasked
The task was *"if a client retries the same order request it should not create two orders."* It never mentions the data model. One unaided run in three rewrote **`prisma/schema.prisma`**; no Strata run touched it.
The wider problem is that you cannot predict which files come back changed. Across three runs of the same prompt, the unaided arm touched **six different files — and only three of them in every run**. Strata touched the same ten files in all three runs: an identical footprint, run to run.
---
## Run it three times. Get the same answer three times.
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/consistency-dark.svg">
<img src="docs/assets/consistency-light.svg" alt="Quality of every individual run. Without Strata the results scatter; with Strata every run of a task lands on the same score." width="760">
</picture>
</div>
| task | without Strata | **with Strata** |
|---|---|---|
| product API | 63%, 75%, 75% | **100%, 100%, 100%** |
| idempotent orders | **14%**, 71%, 71% | **100%, 100%, 100%** |
| payments + queue | 0%, 0%, 50% | 0%, 100%, 100% |
**Zero variance on the tasks the library covers.** Three runs of the same prompt return the same score, three times out of three — against a spread of 26.9 points without it.
That **14%** is not a grading artefact; it repeats on re-grade. That session invented an order API whose create endpoint rejected every request shape it was sent, and because everything else depends on creating an order, five checks collapsed at once. **A cliff, not a slightly worse result** — and nothing in the session's own output says it happened.
---
## Where it does not help
**Payments is on the board with its failures intact.** Both arms shipped a build that does not run: one unaided run never wrote an entry point, and one Strata run pinned `bullmq@5.81.3` beside an incompatible `redis@4.7.1`, which cannot install. Both packages are the model's choice — Strata covers the webhook and nothing else on that task, and the cost ratio lands at 0.95×, a wash.
That is the rule the whole board obeys: **the advantage tracks how much of the task the library covers.** Where coverage is high the numbers above hold. Where it is one capability out of four, Strata is roughly free and roughly neutral.
**Strata also declines outright** when a task is below the point where composing beats writing — about a third of the time.
### Method
Checks were written from the task prompt alone and frozen before the first run. Every check has a negative control proving it can fail. Grading is a separate suite — never `strata/verify.js`, which Strata generates and which would be marking its own homework. Every output tree is archived.
`n=3`, Claude Haiku 4.5, one model per cell. Nothing here speaks to Sonnet or Opus. Cost and token figures move with the model and the prompt; the consistency figures do not.
Full method, per-run scores and every instrument defect found along the way: [`docs/BENCHMARK.md`](docs/BENCHMARK.md).
## Quick start
**Prerequisites:** Node.js ≥ 18 and any MCP client — Claude Code, Cursor, Windsurf, VS Code or Claude Desktop.
```jsonc
// .mcp.json (or claude_desktop_config.json for Claude Desktop)
{
"mcpServers": {
"strata": { "command": "npx", "args": ["-y", "stratalib"] }
}
}
```
Restart the client and ask for a backend feature that needs several parts:
```
Add cursor pagination, per-IP rate limiting and request logging to the products API.
```
Strata reads the project, composes the modules, writes the files, and prints what it created and what it modified. Then:
```bash
npm install && node strata/verify.js
```
> [!NOTE]
> No API key and no account. Modules are served from the hub; the task text is the only thing sent. Your source, schema and files stay on your machine.
---
## The tool
Strata registers exactly one tool. Every tool in an MCP schema is billed on every turn, so the surface is kept to one that does the whole job.
**`strata_use`**
| Argument | Purpose |
|---|---|
| `dir` | Absolute path to the project root — where the schema and conventions are read from |
| `task` | A short label for the work |
| `capabilities` | 3–6 phrases naming the parts of the job. Your model writes these; it has read the whole task |
Returns the files created and modified, the exports available from each module, and the command to verify the result.
---
## How it works
**1 · Reads the project** — locates the ORM and extracts the real entity: fields, types, enums and the actual ID column. Deterministic, in Node, before the model sees a byte. Where the entity cannot be identified with confidence, Strata leaves a slot rather than guessing.
**2 · Selects modules** — each capability phrase is scored against the library, and anything matching on shared vocabulary alone is discarded. Fewer than two surviving modules triggers a decline.
**3 · Composes** — modules contribute to the app rather than owning it, each contribution carrying a rank that fixes its position in the middleware chain. A malformed request throws during body parsing, so logging mounts above it; get that backwards and the one request most worth tracing is the one that loses its correlation id.
**4 · Writes the verifier** — `strata/verify.js` runs each module's own suite, boots the app on a free port, and exercises every requirement against it. Built against your entity, so the checks run on your fields and your routes.
---
## Admission gates
Every module passes six machine-checked gates before it can be served. A module that fails is discarded, not repaired — hand-patching generated modules returns coverage to craft and stops it scaling.
| Gate | Requirement |
|---|---|
| Exports | Loads, and every export it declares resolves at runtime |
| Selftest | Its own suite passes, with a stable assertion count across five runs |
| Adversarial | ≥ 8 assertions, hostile inputs, and assertions that something must **not** happen |
| Compose | Valid fragments with ranks, and declared factories that exist |
| Collisions | No exported name collides with another module |
| Composed boot | Composes with two others into an app that starts and verifies |
The adversarial gate is the one that matters. Every hand-written module in this library shipped with a real bug its own tests did not catch — a 404 that reset a circuit breaker's failure count, a dropped enum constraint, an attacker-controlled request id echoed into a response header. A confirmatory suite admits exactly those.
---
## Repository layout
| Path | Contents |
|---|---|
| `src/` | MCP server: project reading, selection, composition, verifier generation |
| `bin/` | CLI entry point |
| `templates/` | Express skeleton used during composition |
| `benchmark/` | Pre-registered check suites, negative controls, run records and archived output trees |
| `scripts/` | Admission gates, library indexing, selection tests |
Modules are served from the hub; the task text is the only thing sent. Your source, schema and files stay on your machine.
## Documentation
| Document | Subject |
|---|---|
| [`docs/BENCHMARK.md`](docs/BENCHMARK.md) | The full benchmark: method, per-run scores, and every instrument defect found |
| [`CHANGELOG.md`](CHANGELOG.md) | What shipped in each release |
---
## Development
```bash
npm install
node --max-old-space-size=8192 node_modules/typescript/bin/tsc -p tsconfig.mcp.json # build
node scripts/admit-recall.js recalls/<domain>/<name>/v1 # run the gates
node benchmark/quality/negative-control.js # prove the checks can fail
node benchmark/run-quality-battery.js --tasks catalog --max 3 # collect runs
```
`STRATA_MODE=local` composes against a local `recalls/` checkout instead of the hub — required when testing a module that has not been deployed.
---
## Acknowledgements
Built on the Model Context Protocol, Express, Prisma, Mongoose, Drizzle, TypeORM and Sequelize.
## License
AGPL-3.0-or-later. See [`LICENSE`](LICENSE).
---
<div align="center">
<sub>
<a href="https://stratalib.com">stratalib.com</a> · <a href="https://www.npmjs.com/package/stratalib">npm</a> · <a href="https://x.com/stratalib">@stratalib</a>
</sub>
</div>
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues