{"id":50687784,"url":"https://github.com/klarlabs-studio/coverctl","last_synced_at":"2026-06-09T00:04:23.391Z","repository":{"id":329578080,"uuid":"1120087068","full_name":"klarlabs-studio/coverctl","owner":"klarlabs-studio","description":"Coverage feedback for AI coding agents — every language, every change. Domain-aware policy enforcement via MCP server (Claude Code, Cursor, Cline, Aider) and CLI.","archived":false,"fork":false,"pushed_at":"2026-06-06T20:40:28.000Z","size":1428,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-06T21:14:56.643Z","etag":null,"topics":["agent-tools","ai-agents","claude-code","cli","coverage","coverage-testing","cursor","devtools","go","golang","mcp","model-context-protocol","test-coverage"],"latest_commit_sha":null,"homepage":"https://klarlabs-studio.github.io/coverctl/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/klarlabs-studio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-12-20T13:12:02.000Z","updated_at":"2026-06-06T20:40:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/klarlabs-studio/coverctl","commit_stats":null,"previous_names":["felixgeelhaar/coverctl","klarlabs-studio/coverctl"],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/klarlabs-studio/coverctl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klarlabs-studio%2Fcoverctl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klarlabs-studio%2Fcoverctl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klarlabs-studio%2Fcoverctl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klarlabs-studio%2Fcoverctl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/klarlabs-studio","download_url":"https://codeload.github.com/klarlabs-studio/coverctl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klarlabs-studio%2Fcoverctl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34085338,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-tools","ai-agents","claude-code","cli","coverage","coverage-testing","cursor","devtools","go","golang","mcp","model-context-protocol","test-coverage"],"created_at":"2026-06-09T00:04:21.503Z","updated_at":"2026-06-09T00:04:23.380Z","avatar_url":"https://github.com/klarlabs-studio.png","language":"Go","funding_links":["https://github.com/sponsors/felixgeelhaar"],"categories":[],"sub_categories":[],"readme":"# coverctl\n\n**Agent-loop coverage governance — coverage your AI coding agent calls before commit, not a dashboard you read after CI.**\n\n[Get started ↓](#get-started) · [What it looks like ↓](#what-it-looks-like-in-the-agent-loop) · [MCP tools ↓](#mcp-tools) · [CLI reference ↓](#cli-reference) · [Why this exists ↓](#why-this-exists) · [Community ↓](#community)\n\n![MCP](https://img.shields.io/badge/MCP-server-blueviolet) ![Releases](https://img.shields.io/github/v/release/klarlabs-studio/coverctl?label=release)\n\n\u003e *\"Our AI agents ship code fast, but they're blind to coverage policy while editing. We only see breakage in CI, after context is gone, and the same agent then guesses its way to a fix.\"*\n\nWorks best on standard Go/Python/JavaScript/Java/Rust projects with conventional layouts. Mock-heavy code or exotic monorepos may need an explicit `domains:` block in `.coverctl.yaml`.\n\n## Get started\n\n```bash\nbrew install klarlabs-studio/tap/coverctl\n```\n\nWire into Claude Code (`~/.config/claude-code/mcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"coverctl\": {\n      \"command\": \"coverctl\",\n      \"args\": [\"mcp\", \"serve\"]\n    }\n  }\n}\n```\n\nAsk the agent: *\"Run coverctl check and tell me which domains regressed.\"*\n\nFor Cursor / Cline / Claude Desktop / Aider / Continue / OpenCode and other MCP clients, see [docs/src/content/docs/mcp.mdx](docs/src/content/docs/mcp.mdx). All MCP-capable clients work; `coverctl mcp serve` runs in agent mode by default (3 tools: `check`, `suggest`, `debt`). Use `--mode=ci` for the full nine-tool surface.\n\nValidate the install end-to-end:\n\n```bash\ncoverctl mcp doctor   # PASS/FAIL per step with remediation\n```\n\n## What it looks like in the agent loop\n\n*Rendered for clarity — your client may format tool-calls differently.*\n\n```text\nYou:    Add the email-validation feature to the api domain.\n\nClaude: I'll add EmailValidator + tests in internal/api/email.\n\n  [edits: internal/api/email.go, internal/api/email_test.go]\n\n  Tool call → coverctl check\n  Result   → passed: false; failing: api (78.2%, required 80%)\n             uncovered: internal/api/email.go:42-58 (error paths)\n\n  Tool call → coverctl suggest api\n  Result   → uncovered files: email.go (16 lines), retry.go (4 lines)\n\n  Two error branches in EmailValidator.Validate are uncovered.\n  I'll add cases for empty-input and malformed-domain so api meets\n  the 80% threshold before we commit.\n```\n\nThe regression that used to surface in CI 8 minutes later is fixed in the same agent turn.\n\n**The agent does well:** reads `check` output verbatim, calls `suggest` to find uncovered files, calls `debt` to rank smallest fixes, re-runs `check` to confirm.\n\n**Watch for:** agents lowering thresholds in `.coverctl.yaml` to \"fix\" a failure (it's not a fix). Agents claiming coverage rose without a new `check` call (hallucination). Agents ignoring rejection `error_code` and retrying with the same input.\n\ncoverctl returns deterministic structured signals; the agent's *fix* still needs a human reading. The full contract is in [docs/src/content/docs/mcp.mdx](docs/src/content/docs/mcp.mdx).\n\n## Why this exists\n\nAI coding agents write code blind to coverage. They edit, you commit, the regression surfaces in CI minutes or hours later — too late to course-correct in the same session. Existing coverage tools (Codecov, Coveralls, native `go test -cover`) target humans reading dashboards or PR comments, not agents reasoning inline.\n\ncoverctl is built for the agent loop:\n\n- **Catches regressions before commit.** Coverage feedback in the agent's edit turn — not minutes after CI fails. The wedge metric is regressions caught pre-commit.\n- **Agent-callable via MCP.** Speaks MCP — the multi-vendor agent-tool standard now governed by Anthropic, OpenAI, Google, Microsoft, AWS. Works with every MCP-capable client today; works with whatever ships next without modification.\n- **Polyglot governance, one config.** One `.coverctl.yaml` enforces per-domain thresholds across 15 languages. Agents touch any language; coverage tooling must too.\n- **Local-first.** Your source never leaves the machine. Agent calls coverctl over stdio, not over a SaaS API. No account, no upload, no third-party dependency in the agent's reach.\n- **Hardened MCP surface.** Input + output sanitization defends against prompt-injection through test-runner flags and hostile filenames in coverage profiles (Lethal Trifecta).\n\nThe CLI and MCP server are Apache-2.0 licensed and stay free. A hosted layer for cross-repo coverage history is on the roadmap (see [docs/strategy/monetization-decision.md](docs/strategy/monetization-decision.md)) — additive, not a paywall.\n\n## MCP tools\n\nAgent mode advertises three tools (`check`, `suggest`, `debt`) for reliable agent tool selection. CI mode (`--mode=ci`) adds the rest.\n\n| Tool | Mode | Purpose |\n| --- | --- | --- |\n| `check` | agent + ci | Run tests with coverage and enforce policy. Returns per-domain pass/fail, files, warnings. |\n| `suggest` | agent + ci | Recommend thresholds (`current` / `aggressive` / `conservative`). |\n| `debt` | agent + ci | Coverage gap per domain — where to spend effort, ranked. |\n| `init` | ci | Auto-detect project structure and create `.coverctl.yaml` with domain policies. |\n| `report` | ci | Analyze an existing coverage profile without running tests. |\n| `record` | ci | Record current coverage to history for trend tracking. |\n| `compare` | ci | Diff two coverage profiles. Returns delta, improved/regressed files, domain changes. |\n| `badge` | ci | Generate SVG coverage badge. |\n| `pr-comment` | ci | Post coverage report to GitHub / GitLab / Bitbucket PR. |\n\n### MCP resources (read-only context)\n\n| URI | Content |\n| --- | --- |\n| `coverctl://debt` | Coverage debt as JSON. |\n| `coverctl://trend` | Trend over recorded history. |\n| `coverctl://suggest` | Threshold suggestions. |\n| `coverctl://config` | Detected project config. |\n\n## Security boundaries\n\ncoverctl treats MCP traffic as untrusted in both directions, per the Lethal Trifecta threat model.\n\n- **Input boundary.** Test-runner flags that allow arbitrary code loading (`--rootdir`, `--cov-config`, `-D`, `-I`, `--require`, `--init-script`, `--node-options`, ...) are rejected when they come from MCP. Rejection responses use a stable schema with `error_code` and agent-actionable `remediation`. CLI invocations from a human terminal are not sanitized; the human is the trust boundary there.\n- **Output boundary.** User-controlled strings flowing *back* to the agent (filenames in coverage profiles, test names, profile-derived paths, PR description content in `pr-comment`) are canonicalized before return. Prevents return-trip prompt injection through a hostile PR or attacker-named test file.\n\ncoverctl is local-first. The default install transmits nothing — no telemetry, no analytics, no source data. An opt-in `--mcp-telemetry` flag emits structured tool-call events to stderr for users who want to instrument their own pipelines (format documented in [docs/design/mcp-metrics-spec.md](docs/design/mcp-metrics-spec.md)). Adversarial evals (50+ scenarios under [internal/eval/](internal/eval/)) gate every release on rejection-schema integrity and prompt-injection resistance.\n\nFull threat model + residual risk: [docs/security/mcp-threat-model.md](docs/security/mcp-threat-model.md).\n\n## CLI reference\n\nThe CLI is the substrate behind the MCP server; humans can use it directly.\n\n| Command | Purpose |\n| --- | --- |\n| `init` / `i` | Interactive wizard, auto-detects language and domains. `--no-interactive` for CI. |\n| `check` / `c` | Run coverage and enforce policy. `-o json` for machine output, `--fail-under N`, `--ratchet`, `--from-profile`. |\n| `run` / `r` | Produce coverage artifacts without policy evaluation. |\n| `watch` / `w` | Re-run coverage on file change during development. |\n| `report` | Evaluate an existing profile. `-o html`, `--uncovered`, `--diff \u003cref\u003e`, `--merge \u003cprofile\u003e`. |\n| `detect` | Auto-detect domains and write config. `--dry-run` to preview. |\n| `badge` | SVG coverage badge. `--style flat-square`. |\n| `compare` | Diff two profiles. |\n| `debt` | Coverage debt report. |\n| `trend` | Coverage trend from recorded history. |\n| `record` | Append current coverage to history. `--commit`, `--branch` for CI. |\n| `suggest` | Threshold suggestions. `--write-config` to apply. |\n| `pr-comment` | Post coverage to GitHub/GitLab/Bitbucket PR. |\n| `ignore` | Show configured excludes and tracked domains. |\n| `mcp serve` | Start MCP server (stdio). `--mode=agent\\|ci\\|auto`. |\n| `mcp doctor` | First-run validation: PASS/FAIL per step with remediation. |\n| `survey` | Sean Ellis 40% PMF prompt; appends to `~/.coverctl/survey.jsonl`. |\n\nGlobal flags: `-q/--quiet`, `--no-color`, `--ci` (combines quiet + GitHub Actions annotations).\n\n### Test-execution flags\n\n`check`, `run`, `record` accept toolchain flags forwarded to the underlying test runner:\n\n| Flag | Example |\n| --- | --- |\n| `--tags` | `--tags integration,e2e` |\n| `--race` | (Go race detector) |\n| `--short` | Skip long-running tests |\n| `-v` | Verbose test output |\n| `--run` | `--run TestFoo` |\n| `--timeout` | `--timeout 30m` |\n| `--test-arg` | Repeatable: `--test-arg=-count=1 --test-arg=-parallel=4` |\n| `--language` / `-l` | Override autodetection: `go`, `python`, `nodejs`, `rust`, `java`, ... |\n\n### Terminal flow (without an agent)\n\nIf you prefer running coverctl directly:\n\n```bash\ncoverctl init      # auto-detect language + domains, write .coverctl.yaml\ncoverctl check     # enforce policy; exit 1 on violation\ncoverctl suggest --strategy current\ncoverctl record\n```\n\nIf a step fails: `coverctl detect --dry-run` previews `init` output; `coverctl check -o json` surfaces structured failure detail; `coverctl record --commit \"$(git rev-parse HEAD)\" --branch \"$(git rev-parse --abbrev-ref HEAD)\"` provides metadata explicitly in CI.\n\n## Configuration\n\n`.coverctl.yaml` (schema: [`schemas/coverctl.schema.json`](schemas/coverctl.schema.json)):\n\n```yaml\nversion: 1\npolicy:\n  default:\n    min: 75\n  domains:\n    - name: auth\n      match: [\"./internal/auth/...\"]\n      min: 90       # critical path — stricter\n    - name: api\n      match: [\"./internal/api/...\"]\n      min: 80\n    - name: utils\n      match: [\"./internal/utils/...\"]\n      # falls back to default min: 75\nexclude:\n  - internal/generated/*\n```\n\nPer-domain enforcement is the point: overall coverage hides regressions in critical paths. coverctl evaluates each domain against its own minimum and fails the build if any domain falls below.\n\n### Advanced\n\n```yaml\nfiles:\n  - match: [\"internal/core/*.go\"]\n    min: 90                          # per-file overrides\ndiff:\n  enabled: true\n  base: origin/main                  # only enforce on changed files\nintegration:\n  enabled: true                      # Go 1.20+ GOCOVERDIR integration tests\n  packages: [\"./internal/integration/...\"]\n  cover_dir: \".cover/integration\"\n  profile: \".cover/integration.out\"\nmerge:\n  profiles: [\".cover/unit.out\", \".cover/integration.out\"]\nannotations:\n  enabled: true                      # // coverctl:ignore, // coverctl:domain=NAME\n```\n\nMulti-package monorepo? Use `extends:` for inherited policies. Starting point: copy `templates/coverctl.yaml`.\n\n## Supported languages\n\n| Language | Format | Detection markers |\n| --- | --- | --- |\n| Go | Native cover profile | `go.mod`, `go.sum` |\n| Python | Cobertura, LCOV | `pyproject.toml`, `setup.py`, `requirements.txt` |\n| TypeScript / JavaScript | LCOV | `tsconfig.json`, `package.json` |\n| Java | JaCoCo, Cobertura | `pom.xml`, `build.gradle` |\n| Rust | LCOV (cargo-llvm-cov) | `Cargo.toml` |\n| C# / .NET | Cobertura (coverlet) | `*.csproj`, `*.sln` |\n| C / C++ | LCOV (gcov/lcov) | `CMakeLists.txt`, `meson.build` |\n| PHP | Cobertura (PHPUnit) | `composer.json`, `phpunit.xml` |\n| Ruby | LCOV (SimpleCov) | `Gemfile`, `Rakefile` |\n| Swift | LCOV (llvm-cov) | `Package.swift` |\n| Dart | LCOV (dart test) | `pubspec.yaml` |\n| Scala | Cobertura (scoverage) | `build.sbt` |\n| Elixir | LCOV (mix test) | `mix.exs` |\n| Shell | Cobertura (kcov) | `*.bats` |\n\n## GitHub Action\n\n```yaml\njobs:\n  coverage:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - uses: actions/setup-go@v6\n        with:\n          go-version: \"1.25\"\n      - uses: ./.github/actions/coverctl\n        with:\n          command: check\n          config: .coverctl.yaml\n          output: text\n```\n\n## For platform \u0026 devex teams\n\nStandardizing coverage policy across many polyglot repos? coverctl ships with the artifacts your security and procurement reviews will ask for:\n\n- [MCP threat model](docs/security/mcp-threat-model.md) — input + output boundary controls, prompt-injection defense, residual risks.\n- [Rejection schema reference](docs/src/content/docs/mcp.mdx) — stable `error_code` + `remediation` contract for agent recovery.\n- [GTM funnel metrics spec](docs/design/gtm-metrics-spec.md) — what's instrumented and how telemetry stays opt-in.\n\nConsidering coverctl org-wide? Open a GitHub issue with label `platform-evaluation` — happy to walk through architecture and trust boundaries.\n\n## Community\n\n- **Claude Code Plugin Marketplace** — install `coverctl` directly via `/plugin install`.\n- **MCP Registry** — listed at [registry.modelcontextprotocol.io](https://registry.modelcontextprotocol.io).\n- **GitHub Discussions** — [go.klarlabs.de/coverctl/discussions](https://github.com/klarlabs-studio/coverctl/discussions).\n- **Sponsor coverctl development** — [github.com/sponsors/felixgeelhaar](https://github.com/sponsors/felixgeelhaar).\n\nUsed coverctl for a few weeks? Run `coverctl survey` to share PMF feedback (local-only by default; nothing transmitted unless you opt in).\n\nBuilt by Felix Geelhaar with contributions from the polyglot AI-coding community.\n\n## Contributing\n\n- TDD: tests before behavior changes.\n- Coverage ≥80% (`go test ./... -cover`).\n- Conventional Commits (`feat:`, `fix:`, `chore:`, ...) for Relicta version-bump logic.\n- `main` is protected; merge via PR after CI green (`.github/workflows/go.yml` + `.github/workflows/eval.yml`).\n- Run `gofmt -w` and `golangci-lint v2` before pushing.\n\nArchitecture details for contributors: [ARCHITECTURE.md](ARCHITECTURE.md).\n\n## Releases\n\nManaged by [Relicta](https://github.com/felixgeelhaar/relicta). Do not push `v*` tags manually.\n\n## Security\n\nSee [SECURITY.md](SECURITY.md) for disclosure policy. MCP-input sanitization (`internal/mcp/sanitize.go`) and output canonicalization (`internal/mcp/sanitize_output.go`) are the primary defenses against prompt-injection-driven argument and content attacks; report bypasses privately.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklarlabs-studio%2Fcoverctl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fklarlabs-studio%2Fcoverctl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklarlabs-studio%2Fcoverctl/lists"}