TestAtlas.Cli 0.1.6

There is a newer version of this package available.
See the version list below for details.
dotnet tool install --global TestAtlas.Cli --version 0.1.6
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local TestAtlas.Cli --version 0.1.6
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=TestAtlas.Cli&version=0.1.6
                    
nuke :add-package TestAtlas.Cli --version 0.1.6
                    

<h1 align="center"> <img src="assets/logo-mark.svg" width="40" height="40" alt="" valign="middle">  TestAtlas </h1>

<p align="center"> <strong>A queryable, semantic map of your .NET test-automation solution — in one SQLite file, served to your AI agent over MCP.</strong> </p>

<p align="center"> <em>Zero config  ·  No AI  ·  No network  ·  Deterministic</em> </p>

<p align="center"> <a href="https://www.nuget.org/packages/TestAtlas.Mcp"><img alt="TestAtlas.Mcp on NuGet" src="https://img.shields.io/nuget/v/TestAtlas.Mcp?logo=nuget&label=TestAtlas.Mcp&color=004880"></a> <a href="https://www.nuget.org/packages/TestAtlas.Cli"><img alt="TestAtlas.Cli on NuGet" src="https://img.shields.io/nuget/v/TestAtlas.Cli?logo=nuget&label=TestAtlas.Cli&color=004880"></a> <img alt=".NET 8.0" src="https://img.shields.io/badge/.NET-8.0-512BD4?logo=dotnet&logoColor=white"> <img alt="MIT license" src="https://img.shields.io/badge/license-MIT-blue"> </p>

<p align="center"> <img alt="Model Context Protocol — listed" src="https://img.shields.io/badge/Model_Context_Protocol-listed-7C3AED"> <img alt="transport stdio" src="https://img.shields.io/badge/transport-stdio-555"> <img alt="auth none" src="https://img.shields.io/badge/auth-none-2ea44f"> <img alt="hosting local" src="https://img.shields.io/badge/hosting-local-555"> <img alt="no AI, offline, deterministic" src="https://img.shields.io/badge/no_AI-offline,_deterministic-brightgreen"> </p>

<p align="center"> <sub><b>MCP tools</b></sub><br> <code>stats</code>  ·  <code>impact</code>  ·  <code>search_steps</code>  ·  <code>search_scenarios</code>  ·  <code>list_endpoints</code> </p>

<p align="center"> <a href="#-quick-start">Quick start</a> · <a href="#-commands">Commands</a> · <a href="#-use-it-from-an-ai-agent-mcp">MCP</a> · <a href="#-see-it-on-a-real-sample">Sample</a> · <a href="#-keeping-the-map-fresh">Keeping fresh</a> · <a href="#-roadmap">Roadmap</a> </p>


⚡ Add to your AI agent

dotnet tool install --global TestAtlas.Mcp     # the MCP server  (and TestAtlas.Cli to build maps)

Point your agent at it via .mcp.json — Visual Studio, VS Code / Copilot, or Claude Code:

{ "servers": { "testatlas": { "type": "stdio", "command": "testatlas-mcp", "args": ["C:\\path\\to\\codemap.db"] } } }

Run testatlas index <your-solution> first to produce the codemap.db, then point the config at it. Pass the map path explicitly (as above, or via a TESTATLAS_DB env var) — most agents launch the server from their own working directory, not your solution folder, so relying on auto-discovery of a codemap.db in the current directory makes the server exit with code 2. Full setup — agent registration, map auto-discovery, and running from source — is in Use it from an AI agent.


What it does

TestAtlas statically analyses a .NET test-automation solution and emits a semantic map — codemap.db, a single SQLite file — that captures:

  • Projects and their dependency edges
  • Gherkin features, scenarios, and steps
  • Step definitions and their bindings (bound / unbound / ambiguous)
  • Page objects, API clients, helpers, and test classes
  • The call and usage edges that connect them all

…and turns that map into precise answers:

Capability What you get
🔍 Search FTS5 over step definitions + scenarios — "does a step for this already exist?"
💥 Impact Blast radius — the scenarios affected by changing a class, method, step, or endpoint
📊 Report A self-contained HTML drill-down of the whole map
🕸️ Map A self-contained project-dependency graph (HTML)
🔌 MCP Serve the map to an AI agent over stdio — no context stuffing
📈 Stats Entity counts, class-kind breakdown, binding coverage, diagnostics

All of it offline, deterministic, and reproducible — same input, same map, every time.

The indexer spec uses "CodeMap" as the working name for the tool/CLI (testatlas verb, codemap.db output). The repository and product are TestAtlas.


Why

Large test-automation solutions are hard to navigate — for humans and for AI agents. Asked to automate a new story, an agent can't see where similar code lives, which steps already exist, or what conventions the solution follows. So it duplicates steps and misplaces code.

TestAtlas indexes the solution once and hands both people and agents a structured map to answer those questions — deterministically, without a model or a network call.


🚀 Quick start

Requires .NET SDK 8.0+

Install the CLI as a global .NET tool from NuGet:

dotnet tool install --global TestAtlas.Cli

…then, from any directory:

# Index a solution → produces ./codemap.db
testatlas index path/to/YourSolution.sln

# Explore it
testatlas stats
testatlas search "login"
testatlas report        # writes codemap.html
testatlas map           # writes codemap-map.html

Run index with no path — or point it at a folder — and TestAtlas auto-discovers a single .sln/.csproj there. The map is written atomically to ./codemap.db.

<details> <summary><b>Or run from source</b> (no install)</summary>

git clone https://github.com/Karzone/TestAtlas.git
cd TestAtlas
dotnet build TestAtlas.sln
dotnet run --project src/CodeMap.Cli -- index path/to/YourSolution.sln

</details>


🛠 Troubleshooting

<details> <summary><b><code>dotnet tool install</code> fails with <code>401 Unauthorized</code> on a corporate machine</b></summary>

<br>

If your machine has a private, authenticated NuGet feed configured (e.g. Azure DevOps Artifacts), dotnet queries every registered source during install and fails with 401 on the private one — even though TestAtlas is published on public nuget.org.

Install using only nuget.org. Create a minimal public.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  </packageSources>
</configuration>

…then point the install at it:

dotnet tool install --global TestAtlas.Cli --configfile ./public.config
dotnet tool install --global TestAtlas.Mcp --configfile ./public.config

The <clear /> drops every inherited source (including the private feed), so dotnet only sees nuget.org. It's a one-off override — it doesn't change your machine's NuGet configuration or affect the private feed for your other projects.

</details>


📖 Commands

Command What it does
index [<path>] Analyse a .sln/.csproj and write the map (default ./codemap.db).
stats [<db>] Entity counts per project, unbound/ambiguous steps, diagnostics.
search [<db>] <query> FTS5 full-text search over step definitions and scenarios.
impact [<db>] --class\|--method\|--step\|--endpoint <target> Blast radius: scenarios affected by changing an entity.
report [<db>] Write a self-contained HTML drill-down of the map.
map [<db>] Write a self-contained project dependency graph (HTML).
validate [<db>] Check a file is a supported TestAtlas map.

<details> <summary><strong>Options & exit codes</strong></summary>

<br>

index  --output <file> · --config <file> · --include <glob> (repeatable) · --exclude <glob> (repeatable) · --verbose · --quiet

search  --steps (step definitions only) · --scenarios (scenarios only)

Exit codes  0 ok · 1 completed with warnings · 2 fatal · 3 bad arguments

Run testatlas --help for the full usage text.

</details>


🧭 Example workflow

# 1. (Optional) Build the solution — see the note below; the map is the same either way
dotnet build YourSolution.sln

# 2. Index it
testatlas index YourSolution.sln --output atlas.db

# 3. Before writing a new step — does one already exist?
testatlas search atlas.db "add a product to the cart" --steps

# 4. About to change a shared client — what will it hit?
testatlas impact atlas.db --class ProductsApiClient

# 5. Share a human-readable snapshot
testatlas report atlas.db --html atlas.html

# 6. See how the projects depend on each other
testatlas map atlas.db --html atlas-map.html

You do not need to build the solution before indexing it. TestAtlas is a syntax-only pass — it never asks Roslyn for a compilation or a semantic model — so a solution whose NuGet packages have never been restored indexes fine. Gherkin is parsed from the .feature files themselves, and step definitions are read from the [Given]/[When]/[Then] attributes in your source; the code-behind a build generates (*.feature.cs under obj/) is deliberately skipped, so building produces nothing the indexer consumes. Build first only if you want the solution compiled for your own reasons.


🔌 Use it from an AI agent (MCP)

TestAtlas ships an MCP server — testatlas-mcp — that serves the map to any MCP-aware client (Claude Code, and other agents) over stdio JSON-RPC. The agent asks a precise question and gets an exact, structured answer straight from the .db — instead of stuffing source files into its context window.

It's published on NuGet as an MCP-server package (TestAtlas.Mcp), so MCP-aware editors can discover and launch it. The server resolves the map in this order: a path argument, the TESTATLAS_DB environment variable, or a codemap.db/atlas.db in the current working directory. Pass the path explicitly — most agents launch the server from their own working directory, not your solution folder, so auto-discovery usually finds nothing and the server exits with code 2.

Visual Studio / VS Code (GitHub Copilot agent mode) — add to your .mcp.json (%USERPROFILE%\.mcp.json or <SolutionDir>\.mcp.json):

{
  "servers": {
    "testatlas": {
      "type": "stdio",
      "command": "dnx",
      "args": ["TestAtlas.Mcp", "--yes", "C:\\path\\to\\codemap.db"]
    }
  }
}

dnx (from the .NET 10 SDK) fetches and runs the server on demand — no pre-install. Keep the map path as the final arg (double-backslash it on Windows). You can drop the path if the agent launches the server from the folder holding your codemap.db, but most don't — so passing it explicitly is the reliable form. In Visual Studio you can also use Tools picker → + → Add custom MCP server to write this entry for you.

dnx ships with the .NET 10 SDK. If you're on .NET 8/9 (no dnx command), install the tool instead — dotnet tool install --global TestAtlas.Mcp — and change the config above to "command": "testatlas-mcp", "args": ["C:\\path\\to\\codemap.db"]. (This is also what NuGet's auto-generated snippet uses dnx for, so swap it the same way there.)

Claude Code — install the global tool and register it:

dotnet tool install --global TestAtlas.Mcp
claude mcp add testatlas -- testatlas-mcp        # run where a codemap.db lives, or append a path
claude mcp list                                  # the testatlas row should read: ✔ Connected

By default the server is registered for the current project (--scope local). Add --scope user to make it available in every project on your machine, or --scope project to share the registration with your team via a committed .mcp.json.

<details> <summary><b>Or run from source</b> (no install)</summary>

dotnet build src/CodeMap.Mcp -c Release
# on Windows the binary is TestAtlas.Mcp.exe; on macOS/Linux it's TestAtlas.Mcp
claude mcp add testatlas -- src/CodeMap.Mcp/bin/Release/net8.0/TestAtlas.Mcp.exe path/to/codemap.db

</details>

Tools exposed:

  • stats — summary counts: projects, classes, methods, class-kind breakdown, endpoints, and edge tallies.
  • impact — blast radius of a change: the scenarios affected by a given class, method, step definition, or endpoint.
  • search_steps — full-text search over step definitions (expression text + method + class name).
  • search_scenarios — full-text search over scenarios (feature + scenario name + step text + tags).
  • list_endpoints — the HTTP endpoints the suite calls, each with verb, route, and scenario blast radius (highest-reach first).
  • resolve_step — resolve a Gherkin phrase to the existing step definition(s) that would bind it (regex/cucumber, keyword-agnostic). exact / ambiguous / none (+ near-match suggestions ranked by shared terms). Reuse-first authoring: don't write a step that already exists.
  • get_scenario — full detail of scenario(s) by name: feature, tags, kind, example-row count, and the ordered steps.
  • get_step_definition — full detail of step definition(s) by expression: keyword, params, C# class/method/signature, and the scenarios that use it.
  • step_catalog — the reusable step vocabulary with extracted placeholders and allowed values (cucumber {type}, regex (a|b) enums). Compose scenarios from what exists.
  • list_tags — the tag taxonomy with per-tag scenario counts, most-used first — tag new scenarios consistently.
  • project_dependencies — the implied project dependency graph (depends-on / depended-on-by), e.g. "what depends on the Party project?".

MCP clients load servers at session start. If you register the server mid-session, restart your Claude Code / agent session before the testatlas tools appear.

Retrieval runs locally against the SQLite file — deterministic, offline, and a few hundred tokens per answer instead of feeding the whole solution to the model. Protocol details in specs/codemap-mcp.md.

Verify it's working

Don't ask the agent "are you using testatlas?" — models don't reliably introspect their own tool calls, and a confident "no" (or a suggestion to "create an index" — that's the editor's own workspace index, unrelated to TestAtlas) proves nothing. Check these signals instead:

  1. Is the server connected? Open the tools/wrench menu in the chat input — testatlas and its tools (stats, impact, search_steps, search_scenarios, list_endpoints) should be listed and enabled. If they're missing, the server didn't start — see Troubleshooting.

  2. Force a call with a ground-truth question (in your agent's Agent mode, not a plain chat/ask mode — only agent mode invokes tools):

    Using #testatlas, call the stats tool — how many classes and methods does <a project in your map> have?

    A correct, specific count the model couldn't have guessed = it queried your map. A vague answer = it didn't.

  3. Watch for the tool call itself — the agent renders a tool-invocation card (e.g. testatlas › stats) you can expand to see the exact arguments and raw result.

The first call usually pops a client consent prompt ("This tool is from 'testatlas'…"). That's the editor's standard MCP safety gate — it fires for every MCP server, not just this one. TestAtlas is local and read-only, so it's safe to Allow / Always allow.


🔎 See it on a real sample

The repo ships a self-contained sample solution — samples/SampleShop — a realistic 8-project layout that mixes API tests and UI tests, so the map has plenty of connected nodes and exercises both API-client mapping (real HttpClient clients) and page-object mapping (real Selenium IWebDriver pages):

                       ┌─▶ Api.Catalog  ──┐
Tests.Api  ────────────┼─▶ Api.Cart     ──┤
Tests.E2E  ──┬─────────┴─▶ Api.Identity ──┼─▶ Core   (ApiClientBase : HttpClient)
             └─▶ Ui.Pages ─────────────────┘          (PageBase      : IWebDriver)
Tests.Ui   ────▶ Ui.Pages ──────────────────▶ Core
Project Role
Core base types every client/page inherits (highest in-degree → biggest node)
Api.Catalog / Api.Cart / Api.Identity HttpClient-based API clients
Ui.Pages Selenium page objects (Login / Checkout / Product)
Tests.Api / Tests.Ui / Tests.E2E Reqnroll suites whose steps drive the clients and pages

Two committed outputs, generated by the tool from that solution — the map shows 8 projects and 11 dependencies:

  📊 Sample report — features, scenarios, step bindings, class kinds, API endpoints <br>   🕸️ Sample dependency map — the eight projects and the edges between them

GitHub serves .html as raw source, so the links above route through htmlpreview.github.io. You can also download docs/sample-report.html / docs/sample-map.html and open them locally.

<details> <summary>Reproduce them yourself</summary>

<br>

testatlas index  samples/SampleShop/SampleShop.sln --output sampleshop.db
testatlas report sampleshop.db --html docs/sample-report.html
testatlas map    sampleshop.db --html docs/sample-map.html

</details>


🔄 Keeping the map fresh

TestAtlas answers are deterministic — but only as fresh as the map. Re-index whenever source changes so a query never returns a deterministically stale answer.

Check whether a map is stale

python scripts/check-map-age.py [path/to/map.db]   # defaults to ./codemap.db, then ./atlas.db

It reads the map's generated_utc + solution_path, then scans authored source (*.cs / *.feature) for anything modified since — ignoring generated files (*.feature.cs, *.g.cs, *.designer.cs), bin/obj, and any nested solution.

Exit code Meaning
0 fresh — no source changes since the map was built
1 stale — re-run testatlas index
2 no map — nothing to check

(Python 3, stdlib only — runs on Windows, macOS, Linux.)

Warn automatically after every pull (git hook)

A version-controlled post-merge hook runs the check after each merge / git pull — it only prints, never blocks:

git config core.hooksPath scripts/hooks     # enable once, per clone

The hook auto-detects codemap.db / atlas.db at the repo root, or point it explicitly with export TESTATLAS_DB=/path/to/your/map.db.

How often to re-index

A full re-index is a single static pass — seconds — and its cost scales with solution size, not with how much changed. So re-index on change, not on a timer:

  • Locally — the hook tells you when your map drifted; run testatlas index when it does.
  • In CI — re-index on every merge to your main branch and publish the map as a build artifact (don't commit the binary .db).

High churn (many tests added daily) is not a performance problem — each pass is a fixed cost, so just re-index more often. If a pass ever gets slow on a very large solution, scope it with --include / --exclude.

Re-index in CI (any provider)

Three steps: install the tool → run testatlas index → publish the .db artifact.

<details> <summary><strong>GitHub Actions</strong> — <code>.github/workflows/testatlas.yml</code></summary>

<br>

name: TestAtlas map
on:
  push:
    branches: [ main ]
jobs:
  map:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.0.x'
      - run: dotnet tool install --global TestAtlas.Cli
      - run: testatlas index YourSolution.sln --output codemap.db
      - uses: actions/upload-artifact@v4
        with:
          name: testatlas-map
          path: codemap.db

</details>

<details> <summary><strong>Azure DevOps</strong> — <code>azure-pipelines.yml</code></summary>

<br>

trigger:
  branches:
    include: [ main ]
pool:
  vmImage: ubuntu-latest
steps:
  - task: UseDotNet@2
    inputs:
      packageType: sdk
      version: '8.0.x'
  - script: dotnet tool install --global TestAtlas.Cli
    displayName: Install TestAtlas
  - script: testatlas index YourSolution.sln --output codemap.db
    displayName: Index solution
  - publish: codemap.db
    artifact: testatlas-map

</details>

Any other CI (GitLab CI, Jenkins, TeamCity, CircleCI) follows the same three steps.


📁 Project layout

TestAtlas/
├─ src/
│  ├─ CodeMap.Core/     # analysis engine, model, SQLite storage, HTML builders
│  ├─ CodeMap.Cli/      # thin CLI wrapper — packs as the `testatlas` dotnet tool
│  └─ CodeMap.Mcp/      # MCP server — packs as `testatlas-mcp`
├─ tests/
│  ├─ CodeMap.Tests/    # unit / integration tests
│  └─ fixtures/         # synthetic Reqnroll / SpecFlow / broken-solution shims
├─ samples/             # real projects to point the tool at (SampleShop, ReqnrollLoginDemo)
├─ docs/                # committed sample report + dependency map (HTML)
├─ scripts/             # check-map-age.py + git hooks (map freshness / staleness)
├─ specs/               # codemap-indexer.md, codemap-mcp.md — the full specifications
└─ TestAtlas.sln

See specs/codemap-indexer.md for the complete specification: entity model, classification heuristics, CLI surface, SQLite schema contract, performance targets, and acceptance criteria.


🎯 Design tenets

  • Zero config — a useful map on an unseen solution, no config file required.
  • Solution agnostic — heuristic, overridable detection; no company-specific assumptions.
  • Deterministic & offline — same input ⇒ byte-equivalent logical content; no network, no AI.
  • Graceful degradation — solutions without Gherkin still yield a useful map.
  • Public schema as contract — a versioned SQLite schema, so downstream consumers keep working even if a third party swaps in their own indexer.

🗺️ Roadmap

  • Indexer CLI — C# indexer + documented, versioned SQLite schema (v0.1)
  • HTML visualization — self-contained report + project map generated from the db
  • MCP server — testatlas-mcp exposes the map to AI agents over stdio JSON-RPC
  • Second-language indexer — same schema, contract-tested

📄 License

MIT © 2026 Karthik Kalaiyarasu

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
0.1.15 116 10/11/2026
0.1.14 105 10/11/2026
0.1.13 122 10/4/2026
0.1.12 116 10/4/2026
0.1.11 132 9/26/2026
0.1.10 150 7/30/2026
0.1.9 126 7/30/2026
0.1.8 146 7/30/2026
0.1.7 134 7/30/2026
0.1.6 151 7/29/2026
0.1.5 131 7/29/2026
0.1.4 119 7/29/2026
0.1.3 124 7/29/2026
0.1.2 130 7/29/2026
0.1.1 142 7/24/2026
0.1.0 140 7/24/2026