{
  "markdown": "<!-- mcp-name: io.github.RudrenduPaul/evolveguard -->\n\n# evolveguard\n\n[![CI](https://github.com/RudrenduPaul/evolveguard/actions/workflows/ci.yml/badge.svg)](https://github.com/RudrenduPaul/evolveguard/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/evolveguard-cli.svg)](https://www.npmjs.com/package/evolveguard-cli)\n[![PyPI version](https://img.shields.io/pypi/v/evolveguard-cli.svg)](https://pypi.org/project/evolveguard-cli/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Node](https://img.shields.io/badge/node-%3E%3D20.12-brightgreen)](package.json)\n[![Python versions](https://img.shields.io/pypi/pyversions/evolveguard-cli.svg)](https://pypi.org/project/evolveguard-cli/)\n\n<p align=\"center\">\n<a href=\"#what-it-does\">What it does</a> •\n<a href=\"#quickstart\">Quickstart</a> •\n<a href=\"#cli-command-reference\">CLI reference</a> •\n<a href=\"#agent-native-usage\">Agent-native usage</a> •\n<a href=\"#mcp-server\">MCP server</a> •\n<a href=\"#how-it-compares\">How it compares</a> •\n<a href=\"#faq\">FAQ</a>\n</p>\n\nCatch behavioral drift when a Claude Agent Skill or a Claude Code `MEMORY.md` file edits itself, before the edit ships.\n\n![Terminal recording: npm install -g evolveguard-cli, then evolveguard --version and evolveguard --help, showing the published CLI's command list.](docs/demo.gif)\n\n```bash\n# PyPI -- Python CLI + library (genuine port, not a Node wrapper)\npip install evolveguard-cli\n```\n\n```bash\n# npm -- JavaScript/TypeScript CLI + library\nnpm install -g evolveguard-cli\n```\n\n> [!NOTE]\n> Both packages are live and named consistently: `evolveguard-cli` on PyPI and\n> `evolveguard-cli` on npm (renamed 2026-07-19 from the old plain `evolveguard`,\n> which is now deprecated on both registries). `npm install -g evolveguard-cli` and\n> `pip install evolveguard-cli` both work today; the demo GIFs below were recorded\n> against the published packages, not a local build.\n\n## What it does\n\n```bash\nevolveguard record ./SKILL.md --fixtures ./fixtures.json\n# ... skill gets edited, by a human or an agent ...\nevolveguard check ./SKILL.md\n```\n\n```\nEvolveGuard v0.1.4 -- Regression Check\nskill: monorepo-scanner  baseline: 2026-07-15  fixtures: 1\n\n[DRIFT] fixture: \"scan a monorepo\"  new tool call: fs.write (baseline had none)\n         -> new tool call: fs.write (baseline had none) -- this edit introduces a\n            capability the baseline never used\n\n0 PASS, 1 DRIFT, 0 FAIL\nexit code 1 (DRIFT blocks merge by default; override with --allow-drift)\n```\n\nThat's real output from this repo's own `fixtures/labeled-non-breaking-edits/case-03-add-write-capability/`\ntest case, wired to `filesystem: read-only` becoming `read-write` in the skill's frontmatter.\nReproduce it yourself: `evolveguard record` the `before/SKILL.md` in that folder against its\n`fixtures.json`, then `evolveguard check` the `after/SKILL.md`.\n\n![Terminal recording: evolveguard record against the read-only version of the monorepo-scanner skill, then evolveguard check after the skill is edited to add a filesystem write, showing a DRIFT result and exit code 1.](docs/usage.gif)\n\n## Features\n\n**Static analysis, not a live agent run.** `record` parses a skill file's YAML\nfrontmatter (declared `tools`, `network`, `filesystem`, `scope`, and any bundled\n`hooks`), scans the skill's body text and hook scripts for evidence of network calls\nor filesystem writes, and combines both into a capability surface. `check` re-parses\nthe edited file with the same logic and diffs the result. Neither command runs\n`eval`, shells out to a subprocess, or executes a skill's hook scripts, in either the\nTypeScript or the Python distribution.\n\n**Two-level diffing catches drift a single fixture can miss.** Each fixture's\n`expectedToolCalls` filters the recorded capability surface down to what that fixture\ncares about, but `check` also diffs the skill's _whole_ capability surface separately.\nA new capability that no fixture's `expectedToolCalls` happens to cover still shows\nup as a `surfaceChanges` entry instead of passing silently. Confirmed against this\nrepo's own `case-04-scope-widened` fixture, where a `fs.write` scope widens from\n`./workspace/**` to `./**`.\n\n![Terminal recording: evolveguard check --json against the case-04-scope-widened fixture, showing the widened fs.write scope surfaced in the JSON surfaceChanges output.](docs/demo-3-scope-widened-json.gif)\n\n**0% false positives on a labeled corpus, reproducibly.** `npx vitest run\nsrc/evolveguard/benchmark.test.ts` runs the record/check/diff pipeline against\n`fixtures/labeled-non-breaking-edits/`: 2 cases hand-labeled non-breaking (a wording\ntweak, a typo fix) and 3 labeled breaking (a new write capability, a widened scope, a\nhook script gaining a network call). As of this commit, both non-breaking cases stay\nclean: 0 of 2 flagged as drift. The corpus is small and grows as more real skill edits\nget reported.\n\n**A path-traversal guard on hook scripts.** A skill's declared hook paths are resolved\nand validated against that skill's own directory before being read, including a\nsymlink-escape re-check that runs after the lexical containment check passes\n(`src/evolveguard/paths.ts` and `python/src/evolveguard/paths.py`).\n\n**Every subcommand supports `--json`.** `record`, `check`, and `report` all take a\n`--json` flag and return a stable `schemaVersion`-tagged structure, so a coding agent\ncan call any of them as a subprocess and parse the result directly.\n\n**Two independently maintained, format-compatible distributions.** The npm package\n(TypeScript, repo root) and the PyPI package (Python, `python/`) parse the same\nfrontmatter schema and produce byte-compatible baseline and report JSON. A baseline\nrecorded with one CLI can be checked with the other; see\n[docs/concepts.md](./docs/concepts.md#file-formats-and-cross-distribution-compatibility)\nfor the file-format details.\n\nevolveguard detects changes in what a skill is _declared or shown_ to be capable of.\nIt does not run a live LLM agent or replay a real conversation transcript, so it\ncannot tell you whether an agent would actually behave differently on a given prompt.\nThat is an intentional scope limit, and also why it needs nothing hosted and runs\nfully offline in a pre-commit hook or CI job.\n\n## Quickstart\n\n```bash\n# 1. Record a baseline against a skill and its labeled fixtures\nevolveguard record ./skills/my-skill/SKILL.md --fixtures ./fixtures/my-skill.json\n# writes ./skills/my-skill/.evolveguard-baseline.json\n\n# 2. Edit the skill (by hand, or let an agent edit it)\n\n# 3. Check for drift\nevolveguard check ./skills/my-skill/SKILL.md\n# writes ./evolveguard-report.json, exits 1 if drift was found\n```\n\nA fixtures file is a JSON array of labeled prompts and the tool-call shapes each one is\nexpected to touch:\n\n```json\n[\n  {\n    \"id\": \"scan-a-monorepo\",\n    \"prompt\": \"scan a monorepo\",\n    \"expectedToolCalls\": [{ \"tool\": \"fs.read\" }, { \"tool\": \"fs.write\" }]\n  }\n]\n```\n\n`expectedToolCalls` is optional; omit it and the fixture is treated as exercising the\nskill's entire capability surface. `scopeMatches` (a glob) narrows a tool to a specific\nfilesystem scope, e.g. `{ \"tool\": \"fs.write\", \"scopeMatches\": \"./workspace/**\" }`.\n\n## CLI command reference\n\nGenerated from the actual `--help` output of the installed CLI (verified against both\nthe npm and PyPI builds; flags and defaults are identical across distributions).\n\n<details>\n<summary><code>evolveguard --help</code></summary>\n\n```\nUsage: evolveguard [options] [command]\n\nRegression-testing CLI for self-edited Claude Agent Skills (SKILL.md,\nMEMORY.md) -- golden-transcript record/replay against a skill's own declared\nand inferred capability surface, zero hosted infrastructure.\n\nOptions:\n  -V, --version                  output the version number\n  -h, --help                     display help for command\n\nCommands:\n  record [options] <skillPath>   Record a golden-transcript baseline for a\n                                 skill against a set of labeled fixtures\n  check [options] <skillPath>    Replay the fixtures from a baseline against\n                                 the current (possibly edited) skill and report\n                                 drift\n  report [options] [reportPath]  Print a previously generated\n                                 evolveguard-report.json\n  mcp                            [coming soon] Expose record/check/report as\n                                 MCP tools for a coding agent to call\n                                 mid-session\n  help [command]                 display help for command\n```\n\n</details>\n\n<details>\n<summary><code>evolveguard record --help</code></summary>\n\n```\nUsage: evolveguard record [options] <skillPath>\n\nRecord a golden-transcript baseline for a skill against a set of labeled\nfixtures\n\nArguments:\n  skillPath          path to the SKILL.md or MEMORY.md file to baseline\n\nOptions:\n  --fixtures <path>  path to a fixtures JSON file (array of {id, prompt,\n                     expectedToolCalls?})\n  --baseline <path>  path to write the baseline file (default:\n                     <skill-dir>/.evolveguard-baseline.json)\n  --json             output structured JSON instead of human-readable text\n                     (default: false)\n  -h, --help         display help for command\n```\n\n</details>\n\n<details>\n<summary><code>evolveguard check --help</code></summary>\n\n```\nUsage: evolveguard check [options] <skillPath>\n\nReplay the fixtures from a baseline against the current (possibly edited) skill\nand report drift\n\nArguments:\n  skillPath          path to the SKILL.md or MEMORY.md file to check\n\nOptions:\n  --baseline <path>  path to the baseline file (default:\n                     <skill-dir>/.evolveguard-baseline.json)\n  --report <path>    path to write the report file (default:\n                     \"./evolveguard-report.json\")\n  --allow-drift      exit 0 even if drift is detected (drift is still reported)\n                     (default: false)\n  --json             output structured JSON instead of human-readable text\n                     (default: false)\n  -h, --help         display help for command\n```\n\n</details>\n\n<details>\n<summary><code>evolveguard report --help</code></summary>\n\n```\nUsage: evolveguard report [options] [reportPath]\n\nPrint a previously generated evolveguard-report.json\n\nArguments:\n  reportPath  path to the report file (default: \"./evolveguard-report.json\")\n\nOptions:\n  --json      output structured JSON instead of human-readable text (default:\n              false)\n  -h, --help  display help for command\n```\n\n</details>\n\n**Exit codes:** `0` all fixtures PASS and no surface-level drift, `1` at least one DRIFT\nwas found (pass `--allow-drift` to still exit 0 while still reporting it), `2` a usage\nerror or a file that failed to parse.\n\n> [!WARNING]\n> The npm build's `evolveguard --version` currently prints `0.1.0` even though the\n> published package is at a newer `package.json` version; the PyPI build reads its version\n> from installed package metadata and reports it correctly. Use the badges above, not\n> `--version`, if you need the exact currently-published version number of the npm package.\n\n## Agent-native usage\n\nEvery subcommand supports `--json` for structured output an agent can parse directly:\n\n```bash\nevolveguard check ./SKILL.md --json\n```\n\n```json\n{\n  \"schemaVersion\": 1,\n  \"skillName\": \"monorepo-scanner\",\n  \"results\": [\n    {\n      \"id\": \"scan-a-monorepo\",\n      \"verdict\": \"DRIFT\",\n      \"changes\": [\n        /* ... */\n      ]\n    }\n  ],\n  \"surfaceChanges\": [],\n  \"summary\": { \"pass\": 0, \"drift\": 1, \"total\": 1 },\n  \"exitCode\": 1\n}\n```\n\n> [!NOTE]\n> The Python distribution ships a real MCP server (see [MCP server](#mcp-server) below).\n> The npm/TypeScript distribution's `evolveguard mcp` subcommand is still a\n> \"coming soon\" stub; until it ships, call `record`/`check`/`report --json` directly as\n> a subprocess from your coding agent, or use the Python MCP server even if the rest of\n> your toolchain is on the npm package.\n\n## MCP Server\n\nThe Python distribution (`evolveguard-cli` on PyPI) ships a Model Context Protocol\nserver, so an MCP-compatible agent (Claude Desktop, Claude Code, etc.) can call\nevolveguard directly instead of shelling out and parsing text. The npm/TypeScript\ndistribution does not ship one yet -- its `evolveguard mcp` subcommand remains a stub.\n\n```bash\npip install \"evolveguard-cli[mcp]\"\n```\n\nAdd it to your MCP client's config, for example Claude Desktop's\n`claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"evolveguard\": {\n      \"command\": \"evolveguard-mcp\"\n    }\n  }\n}\n```\n\nIt exposes a single tool, `run(args: list[str])`, that shells out to the installed\n`evolveguard` CLI with the exact argv you'd type at a terminal and returns\n`{returncode, stdout, stderr, json?}` (or `{error: ...}` if the command fails, times\nout, or exits non-zero) -- so one tool covers `record`, `check`, and `report` without a\nbespoke MCP tool per subcommand. Example call from an agent:\n\n```json\n{ \"tool\": \"run\", \"arguments\": { \"args\": [\"check\", \"./SKILL.md\", \"--json\"] } }\n```\n\nwhich returns the same structured report `evolveguard check ./SKILL.md --json` would\nprint, plus the raw `returncode`/`stdout`/`stderr`.\n\n## Library API\n\nevolveguard also exports a programmatic API for the same pipeline, for teams who want\nto integrate it into their own tooling instead of shelling out to the CLI. Both\ndistributions expose the same functions and the same JSON-compatible file format; a\nbaseline recorded with one CLI can be checked with the other (see\n[docs/concepts.md](./docs/concepts.md#file-formats-and-cross-distribution-compatibility)).\n\n**TypeScript:**\n\n```ts\nimport {\n  recordBaseline,\n  replaySkill,\n  diffAll,\n  writeBaseline,\n  readBaseline,\n} from 'evolveguard';\n\nconst baseline = recordBaseline('./SKILL.md', './fixtures.json');\nwriteBaseline('./.evolveguard-baseline.json', baseline);\n\n// ... skill gets edited ...\n\nconst saved = readBaseline('./.evolveguard-baseline.json');\nconst replay = replaySkill('./SKILL.md', saved);\nconst report = diffAll(saved, replay);\n```\n\nSee `src/evolveguard/index.ts` for the full exported surface: `parseSkillFile`,\n`deriveCapabilitySurface`, `loadSkill`, `buildFixtureSnapshots`, `loadFixtures`,\n`recordBaseline`, `replaySkill`, `diffFixture`, `diffAll`, `diffSurface`, `writeBaseline`,\n`readBaseline`, `writeReport`, `readReport`, plus the shared `types.ts` interfaces.\n\n**Python** (`pip install evolveguard-cli`):\n\n```python\nfrom evolveguard import record_baseline, replay_skill, diff_all, write_baseline, read_baseline\n\nbaseline = record_baseline(\"./SKILL.md\", \"./fixtures.json\")\nwrite_baseline(\"./.evolveguard-baseline.json\", baseline)\n\n# ... skill gets edited ...\n\nsaved = read_baseline(\"./.evolveguard-baseline.json\")\nreplay = replay_skill(\"./SKILL.md\", saved)\nreport = diff_all(saved, replay)\n```\n\nSee [`python/README.md`](./python/README.md) for the Python-specific walkthrough and\nthe same exported surface under `evolveguard/__init__.py`.\n\n## How it compares\n\n**Braintrust** is a general LLM eval and observability platform. It is a strong choice\nif you are already logging traces from a live agent and want statistical eval scoring\nacross runs, but it needs SDK integration and an eval-definition step per app.\nevolveguard needs neither: point it at one `SKILL.md` file and a fixtures JSON, and it\nworks.\n\n**[agent-eval](https://github.com/RudrenduPaul/agent-eval)** (this same author's other\nrepo) answers a different question: whether an agent's behavior changed between two\nversions you define, for any agent, framework-agnostic, by running both versions\nyourself and computing a p-value on the difference. evolveguard is triggered directly\nby a file diff on `SKILL.md`/`MEMORY.md` and answers whether _this specific edit_\nchanged the capability surface a baseline recorded. It parses the skill artifact\nitself and never asks you to define or run anything live.\n\n|                | evolveguard                                  | Braintrust                         | agent-eval                                |\n| -------------- | -------------------------------------------- | ---------------------------------- | ----------------------------------------- |\n| Setup          | `record` + `check` against one file          | SDK integration, eval definitions  | Define and run two agent versions         |\n| Trigger        | `SKILL.md`/`MEMORY.md` file diff             | Manual eval run                    | Manual A/B run                            |\n| Mechanism      | Static capability-surface diff               | Live-run trace scoring             | Statistical behavior comparison (p-value) |\n| Hosted infra   | None                                         | Hosted platform                    | None                                      |\n| Live LLM calls | None                                         | Yes (scores real runs)             | Yes (runs both versions)                  |\n| Best for       | Self-edited Claude Agent Skills specifically | General LLM app eval/observability | Any agent, generic A/B regression         |\n\n## What is evolveguard, and why does it exist\n\nevolveguard is a command-line tool and TypeScript library that detects capability drift\nin Claude Agent Skill files (`SKILL.md`) and Claude Code auto-memory files (`MEMORY.md`)\nafter they are edited, by a human or by an agent. It works by parsing a skill's declared\nfrontmatter scope and any static evidence of network or filesystem-write behavior in its\nbody text and bundled hook scripts, snapshotting that as a baseline, and re-deriving the\nsame snapshot after an edit to diff against it. It exists because Claude Code's Agent\nSkills ecosystem lets skills and memory files change an agent's behavior without a\nhuman necessarily reviewing every edit for regression, and no existing tool checks that\nspecific artifact shape without requiring SDK integration or a live agent run.\n\n## Status\n\nThis is a v0.1 release: a small, focused addition to the existing Claude Agent Skills\necosystem. It ships fully MIT-licensed with no proprietary tier, as two independent,\nequally first-class packages:\n\n- **PyPI (`evolveguard-cli`, Python)**, live at\n  [pypi.org/project/evolveguard-cli](https://pypi.org/project/evolveguard-cli/). A\n  genuine independent port, not a wrapper around the Node binary (see\n  [`python/README.md`](./python/README.md)). `pip install evolveguard-cli` installs it\n  directly. The package was originally published under the name `evolveguard`; that\n  older PyPI project is retired and no longer receives updates, install\n  `evolveguard-cli` instead.\n- **npm (`evolveguard-cli`, TypeScript)**, live at\n  [npmjs.com/package/evolveguard-cli](https://www.npmjs.com/package/evolveguard-cli).\n  `npm install -g evolveguard-cli` installs it directly. Renamed 2026-07-19 from the\n  old plain `evolveguard`, which is now deprecated, to match the PyPI package's\n  naming convention.\n\n## FAQ\n\n**What is evolveguard, exactly?**\nA command-line tool and library that detects capability drift in Claude Agent Skill\nfiles (`SKILL.md`) and Claude Code auto-memory files (`MEMORY.md`) after they are\nedited. It is not a self-evolving agent framework and does not build, run, or host\nagents itself. It is a regression-testing CI gate that reacts to a file diff on a\nskill artifact that already changed, by a human or an agent. See \"What is evolveguard,\nand why does it exist\" above for the full definition.\n\n**Does evolveguard call an LLM?**\nNo. Record and check are both fully static and deterministic; see \"Features\" above for\nexactly what each command parses and scans.\n\n**What's the core differentiator versus a general testing or eval tool?**\nIt needs nothing hosted and nothing to integrate: point it at one `SKILL.md` file and a\nfixtures JSON, and `record`/`check` work immediately, with zero SDK integration and no\nlive agent run. That is the tradeoff the \"How it compares\" table above documents:\nnarrower scope than a general eval platform, in exchange for zero setup.\n\n**How does evolveguard compare to Braintrust?**\nBraintrust is a general LLM eval and observability platform that needs SDK integration\nand an eval-definition step, and it scores real traces from a live agent run.\nevolveguard needs neither; it parses the skill file itself and never calls an LLM. Use\nBraintrust if you are already logging traces and want statistical eval scoring across\nruns. Use evolveguard if you want a pre-commit or CI check that a `SKILL.md`/`MEMORY.md`\nedit did not silently widen what the skill can do. See the comparison table in \"How it\ncompares\" above for the full breakdown, including how it compares to this same author's\n[agent-eval](https://github.com/RudrenduPaul/agent-eval).\n\n**Does it work with `MEMORY.md` files, which have no frontmatter?**\nYes. A file with no frontmatter is parsed with an empty declared scope, so its capability\nsurface comes entirely from static evidence found in the body text.\n\n**What platforms does it run on, and how do I install it?**\nThe npm package requires Node.js >=20.12 (any OS Node supports) and installs with\n`npm install -g evolveguard-cli`. The PyPI package requires Python >=3.9 and installs\nwith `pip install evolveguard-cli`. Both distributions are pure-library/CLI packages\nwith no native bindings, so there is no OS-specific build step on either side.\n\n**What's a real limitation to know about before relying on this?**\nIt only sees _declared or shown_ capability, not runtime behavior. A skill could pass\n`check` and still behave differently on a given prompt in ways that do not touch its\ncapability surface. The false-positive benchmark (see \"Features\" above) is also\ncurrently a small, hand-labeled corpus of 5 before/after pairs, not a large dataset, so\ntreat the 0% figure as a starting measurement, not a statistical guarantee. The Python\ndistribution ships a real MCP server (see \"MCP server\" above); the npm/TypeScript\n`mcp` subcommand is still a \"coming soon\" stub, and the npm build's `evolveguard\n--version` output currently lags the package's real published version (see \"CLI\ncommand reference\" above).\n\n**Is this a general agent-evolution framework?**\nNo. See \"How it compares\" above. evolveguard deliberately does not build or host a\nself-evolving agent framework; it only tests skill/memory edits that already happened.\n\n**Is evolveguard free to use, including commercially?**\nYes. It is MIT-licensed with no proprietary tier or paid version; see\n[LICENSE](LICENSE). You can use, modify, and redistribute it, including in commercial\nprojects, under the standard MIT terms.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md). Every change lands with tests in both\ndistributions; a change to the frontmatter schema, the capability-surface derivation,\nor the diff verdict logic must be made in both `src/evolveguard/` (TypeScript) and\n`python/src/evolveguard/` (Python), with equivalent coverage added to both suites.\n\n## Security\n\nSee [SECURITY.md](SECURITY.md). evolveguard reads local files you point it at and\nnever executes any of them; it makes no network calls and does not run a live agent.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n",
  "bytes": 23145,
  "sha": "5bc94c586672b7d9d2bceca84eba659d59e7716e4dde2be45abe5ed77b13ef54",
  "repo_slug": "rudrendupaul/evolveguard",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_rudrendupaul_evolveguard_ed3a7412/readme"
}