Documentation

From nothing to monitored

Four steps. The first two take about two minutes and are the whole product, steps 3 and 4 are optional and each stands on its own. Prefer to run them yourself? Manual setup covers the same ground without the wizard.

1

Connect the repo

Run this where your agents live. It finds the MCP servers you already call, opens your browser to approve, and takes the first snapshot of every contract. No MCP servers? It sets up execution traces instead, step 4 becomes the whole product.

npx zevruna

The approval page asks you to sign in, then to confirm the code the terminal is showing. Signing in is what makes the project yours: the account, not the token, is what you recover with. Until you approve, the CLI keeps polling, so leave it running and approve in the browser tab it opened.

Servers on localhost. Zevruna polls from the cloud, so it can never reach a server running on your machine, those register as push-only and their contract is captured locally instead. The wizard prints the exact command per server:

zevruna snapshot <name> --push

Run it once now, and from CI so the contract stays current. Same path stdio servers take, for the same reason: the cloud never spawns your processes.

Done when the wizard says either “You’re live” (alerts are on) or “Project ready” with the one step left. It never claims to be watching something it isn’t.

2

Confirm it is really working

Checks the install against reality rather than against your config. Exits 1 while anything is wrong, so it doubles as a CI assertion.

npx zevruna doctor

Done when the last line reads “Zevruna is ready.”

3

Fail the build when a contract breaks

An alert is easy to ignore; a red check is not. Paste this workflow, it gates on the manifests step 1 wrote, and fails the build rather than passing quietly if none are committed.

# .github/workflows/contracts.yml
name: contracts
on:
  push: { branches: [main] }
  pull_request:
  schedule: [{ cron: "0 6 * * *" }]   # nightly: the server drifts, your code doesn't

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npx --yes zevruna@latest check --manifest "agents/*.yaml" --against pinned
        env:
          ZEVRUNA_TOKEN: ${{ secrets.ZEVRUNA_TOKEN }}

Keep the nightly schedule. It is the run that catches a server drifting while nothing in your repo changed, which no test you own can see, because nothing you own changed.

Done when a pull request shows a “contracts” check.

4

Optional, see inside the runs

Steps 1–3 tell you a contract moved. This tells you what your agent actually did. One boundary, wrapped by your coding agent, the wizard already installed the skill it needs.

npx zevruna instrument --json   # ranked candidates, each with a diff
npx zevruna doctor --json       # telemetry_received: ok

By hand it is an install and two lines. See exactly what it sends first if a security review is involved.

Or let your coding agent do it. Step 1 registered our MCP server, so ask it to “set up Zevruna”: propose_instrumentation hands it the ranked boundaries with the exact edit for each, and run_doctor tells it whether a run actually arrived. It proposes, you review the diff, nothing is written unattended.

In Node, wrap on the server, not in the browser. That SDK needs node:async_hooks, which a bundler stubs to an empty object, so a client-side wrap builds green and then throws the moment the chunk evaluates. If your turn loop runs in the browser, wrap the route it calls. Candidates are ranked with this in mind and a browser file is never proposed. Python and Go have no equivalent trap.

Node

npm install @zevruna/observe
import { observeAgent, instrumentMcpClient } from "@zevruna/observe";

const client = instrumentMcpClient(mcpClient, "acme-crm");
await observeAgent({ name: "support-agent" }, () => runSupportAgent(input));

Python

pip install zevruna
from zevruna import observe_agent, instrument_mcp_client

client = instrument_mcp_client(mcp_client, "acme-crm")
async with observe_agent("support-agent"):
    await run_support_agent(user_input)

Go

go get github.com/Kevin-Benelli/zevruna-go
ctx, trace := zevruna.StartTrace(ctx, "support-agent")
defer trace.EndWith(&err)

crm := zevruna.InstrumentMCP(client, "acme-crm")

All three emit the same versioned events and behave identically down to retry backoff and what they refuse to send. The protocol is the contract, and shared fixtures hold them to it in CI.

Already exporting OpenTelemetry? Then skip this step. Point your exporter at https://zevruna.com/api/otlp and your existing spans arrive as runs — two environment variables, no code change.

Every SDK reads ZEVRUNA_TOKEN from the environment, none of them reads .env.zevruna for you, so load that file or set the variable however your runtime already does. Without a token they stay silent rather than throwing: telemetry must never be able to take down the agent it is watching.

Done when doctor reports telemetry_received. Not when the diff looks right, when a run has arrived.

What you have after each step

AfterYou getCosts you
Step 1Every contract you depend on, snapshotted and watched. Alerts naming the affected agents.one command
Step 2Proof it works, rather than a hope.one command
Step 3Broken call sites cannot reach production.one workflow file
Step 4Execution traces, and runs that failed while every call returned 200.one wrapped boundary

When something breaks

You get an alert naming the affected agents and fields. Open the incident, press Accept as new contract, apply the suggested edits, push. The green check is the resolution, nobody clicks resolved, and the exposure window is recorded as proof.

Or let your coding agent do it. Zevruna ships its own MCP server, so claude "fix ZV-2481" pulls the diff, the blast radius and the suggested patch, edits the call sites, and reruns the check, without Zevruna ever holding repo write access.

Step 1 sets this up: the wizard installs the skill and registers the server in your client config. To wire it by hand, or in a client the wizard does not write:

claude mcp add zevruna -- npx -y @zevruna/mcp

The server reads your token from .env.zevruna, so no secret goes in the config file. Without a token it still answers the public tools, and every account-scoped answer says whether it is authenticated, so an empty list is never mistaken for a broken credential.

The same server handles setup, not just repair: propose_instrumentation finds where to wrap a run, run_doctor verifies the install against reality, and list_incidents is where an agent starts when it has no id.

CLI reference

zevruna init [--name <project>]

The wizard. Detects servers from .mcp.json / mcp.json / .cursor/mcp.json, opens the browser for device-flow auth, registers remote servers, scans your code into manifests, and takes the first snapshots. Step 1 is a complete product. It asks what to call the project, defaulting to the directory name; --name answers that without a prompt, which is what CI wants.

zevruna snapshot <endpoint|name> [--push]

Handshake a server and write the canonical, content-hashed snapshot to .zevruna/. --push sends it to the cloud. A bare name resolves against your client config, which is how stdio and localhost servers are monitored: the cloud never spawns your processes and cannot reach your machine.

zevruna remove <name> [--yes]

Stops monitoring a server and deletes its snapshots, drift history and incidents, freeing the plan slot it was using. Names are matched exactly, so a near-miss is refused rather than removing the neighbouring server. It asks before deleting; --yes answers, and without a terminal it refuses instead of assuming yes.

zevruna diff <before.json> <after.json>

Classified redline in your terminal. Exits 1 on any breaking change, so it drops straight into scripts.

zevruna check --manifest agents/*.yaml [--against pinned|.zevruna]

The CI gate. Fails the build when your code sends a field that no longer exists, omits a newly required one, or reads a removed output field. --against pinned checks the cloud's pinned contract; --against .zevruna works air-gapped from committed snapshots.

zevruna scan --server <name> --consumer <agent>

Generates the manifest: which tools this agent calls and which fields it sends, with file and line call sites. Nobody writes these by hand.

zevruna instrument [--json]

Proposes where to wrap agent runs, ranked, an MCP client construction first, since one wrapper instruments every tool call it makes. Emits the actual diff and never edits your code: an agent rewriting a production entry point unattended is confidently wrong in exactly the way this product exists to catch.

zevruna doctor [--json]

Verifies the install against reality rather than against your config: token, API reachability, registered servers, baseline snapshots, manifests, whether runs are actually arriving, and where alerts land. Exits 1 while anything blocks, so it works as a gate.

Public API

The public surface needs no key and is CORS-open, it is meant to be scripted.

POST /api/public/check              { "endpoint": "https://…/mcp" }  → contract report
GET  /api/public/advisories         → the breaking-change feed
GET  /api/public/feed/{server}      → advisories for one server
GET  /api/public/stability/{server} → 90 daily cells: quiet|safe|risky|breaking
GET  /api/public/servers            → the monitored-server directory
GET  /llms.txt                      → citable advisory list for AI assistants

Environment

ZEVRUNA_TOKEN=zv_live_…      # project token, written by the wizard to .env.zevruna
API_BASE=https://zevruna.com/api
ZEVRUNA_TELEMETRY=0          # opt out of anonymous CLI usage events
Check a server freeData collectedGlossaryPricing