Shreyas Sane
Explore

Coding

Runmark

Request definitions as files in your repository, run by one engine that serves a developer's terminal and a coding agent over MCP.

Role
Sole author: product, CLI and MCP design, execution engine, release
Years
Present
Built with
TypeScript, Node.js, Zod, YAML, Model Context Protocol, Turborepo, esbuild, pnpm, Biome, GitHub Actions, npm

Validating an API you are currently changing

You are changing an API. Often an agent is helping. Before and after each change you need to run a real sequence of HTTP calls — authenticate, create something, read it back, exercise the failure path — and know what happened.

The usual tools handle the first request well and the sequence badly. The flow lives in a desktop application, so it is invisible in review and drifts from the code it tests. The run state is inside a session you cannot inspect. If step four fails, step one runs again. And when an agent is the one running the flow, none of it is legible: there is no artifact to read, only a screenshot or a paraphrase.

Runmark answers that shape of problem.

Two directories, and only one is tracked

The whole design rests on one split. The runmark directory describes what should happen, and git tracks it alongside the code it tests. The artifacts directory records what did happen. Git never sees it.

In practice that split decides the product. Because intent is tracked, a request sequence appears in a pull request next to the change it validates, and a reviewer can argue about an assertion the same way they would argue about a test. Because runtime state is separate and durable, a run can pause at a checkpoint and resume later without repeating completed steps, and the record of a failure survives the terminal it happened in.

# yaml-language-server: $schema=https://raw.githubusercontent.com/exit-zero-labs/runmark/main/packages/contracts/schemas/request.schema.json
kind: request
title: Ping
method: GET
url: "{{baseUrl}}/ping"
expect:
  status: 200

ping.request.yamlexit-zero-labs/runmark · examples/getting-started/runmark/requests/

A request is seven lines and one schema reference. The editor validates it before the runner ever sees it.

# yaml-language-server: $schema=https://raw.githubusercontent.com/exit-zero-labs/runmark/main/packages/contracts/schemas/run.schema.json
kind: run
title: Smoke
env: dev
steps:
  - kind: request
    id: ping
    uses: ping

smoke.run.yamlexit-zero-labs/runmark · examples/eval-basic/runmark/runs/

A run composes requests by id. Nothing is duplicated into it, so a request stays one file with one owner.

It also gives secrets an obvious home. Session ledgers are written redacted. Anything sensitive goes into an owner-only companion file beside them, and the audit export path never reads those files. Nobody has to remember to scrub a run record before sharing it.

The same tool for a person and an agent

Runmark ships a CLI and an MCP stdio server in a single installed package, and the rule between them is parity: the same definitions, the same session model, the same artifacts, the same safety rules. Not a reduced agent surface, and not a separate agent product.

Fourteen MCP tools cover what the CLI covers — listing and describing definitions, validating a project, running and resuming, reading session state and artifacts, pulling stream chunks, cancelling, explaining where a variable came from, and exporting an audit summary.

Building both against one engine kept the design honest. Anything an agent could not inspect was something a person could not debug, and the fix was the same in both cases: write it down as an artifact.

The packaging follows from the same idea. The MCP SDK is imported lazily, so someone who only ever runs the CLI does not pay for the agent surface at startup. Agents also tend to launch a server from somewhere other than the repository being tested, so every MCP call has to state its project root explicitly. Inheriting a working directory would quietly test the wrong project.

Refusing before sending

Validation runs before execution, not during it. Schema problems, broken wiring between steps, and unsafe configurations are caught while nothing has left the machine, because the alternative is discovering them halfway through a sequence that has already written to a real system.

Resume has a similar rule. If the tracked definitions changed since a session paused, or another process holds the session lock, continuing could mean executing a flow that no longer matches the record. Runmark refuses and exits with a distinct code, so a script or an agent can tell an unsafe resume apart from a failed request and decide what to do.

The tool sends no product telemetry. The only network traffic is the requests you configured.

Pre-1.0, and saying so

Runmark is pre-1.0 and says so. It is published on npm, open source under MIT, and has been through several releases, including one that folded the separate MCP package into the CLI and one that tightened how agents identify a project.

The execution model and the file layout are settled. The command surface is still moving.

Inside the installed package

One execution engine sits behind both entry points. The filesystem carries the distinction that makes runs reviewable and resumable.

runmark/
Tracked request definitions, environment shape, and expected outcomes. Reviewed like source.
runmark/artifacts/
Git-ignored runtime state: session ledgers, responses, and stream chunks from actual runs.
Execution engine
Validation, sequencing, variable resolution, pause and resume, and artifact writing. Shared by both surfaces.
CLI and MCP server
Two entry points over the same engine, shipped in one package, with identical capabilities and safety rules.