Skip to main content
Glama
Parker-Fawcett

rebuild-dossier

rebuild-dossier

DOI arXiv:2608.23616 M8ven Score CI

An MCP server that reverse-engineers a trustworthy rebuild spec — a locked CLAUDE.md, .claude/ config, and a mutation-tested test suite — out of an existing app, so any coding agent can rebuild it cleanly against that spec instead of guessing.

It does not rebuild the app. It produces the spec, contracts, and tests a coding agent consumes to do that separately. This boundary is deliberate — see Why below.

Validated against a real app. The core loop (ingest, resolve cases, generate spec) has been tested end-to-end against a real, messy repo with two independent fresh-agent handoffs on two model tiers, plus a mutation-tested test suite. docs/v0-findings.md covers what worked, what broke, and what's still open.

Why

Prior research (AgentModernize, arXiv:2605.17535) found that a rebuild pipeline scores 0% behavioral equivalence with no verified feedback loop, and only 9–19% with a coarse one. The bet behind this tool: locking interface contracts before running tests, plus a strict one-test-at-a-time retry loop instead of batch regeneration, does meaningfully better.

The riskiest part of any such pipeline is silently validating a bug as intentional — four sources of evidence can quietly agree on the same mistake with nobody ever having said why. So the single non-negotiable rule in this tool: auto-resolving an ambiguity requires both signal agreement and an affirmative signal that someone actually decided (a stated comment, a TODO admitting a bug, or a direct human answer). Silent agreement alone — code and observed behavior simply matching, with no one ever having said why — always becomes a question, never an auto-resolution, no matter how high the apparent confidence.

Related MCP server: reforge-mcp

How it works

Six MCP tools, run from inside a normal Claude Code (or any MCP-compatible) session:

Tool

What it does

ingest_repo(path)

Static analysis only, no LLM call: routes, package.json, build config (via AST, never executed), existing tests, and structural-smell detectors (e.g. a client-side-only credential check with no server-side verification) that surface real ambiguity even when nobody ever commented on it.

crawl_site(url)

Headless Playwright crawl of reachable routes, with progress notifications so long crawls don't get killed as unresponsive.

flag_known_bug(description)

Free text, stored verbatim. Always overrides auto-resolve for anything it matches — the cheapest, most authoritative signal in the system.

get_case_queue() / resolve_case(id, decision)

The ambiguity queue. Surfaces open questions via MCP elicitation when the client supports it; resolve_case is always available as a scripted fallback.

generate_spec()

Only callable once the case queue is empty. Writes CLAUDE.md, .claude/rules/, .claude/settings.json (hooks that mechanically enforce the discipline — see below), spec/contracts/*.md, tests/visible/ + tests/held-out/, and kickoff-prompt.txt to a clean sibling <repo>-rebuild/ directory — never into the original repo. Runs a real mutation check before finalizing tests: deliberately breaks the original code and confirms each generated test actually catches it, downgrading any that don't.

crawl_site needs Chromium (npx playwright install chromium, step 2 below) — it isn't bundled with the server, including when installed via Smithery, so run it once first or the tool will fail.

Rails that are mechanically enforced, not just written down

A comparison run across two model tiers found that a weaker model will happily read CLAUDE.md, understand "only build what's currently failing, don't batch-regenerate," and then quietly violate it anyway — because nothing checked it. Two rules in this tool are now enforced by real hooks, not prose, for exactly that reason:

  • spec/ is locked. A PreToolUse hook blocks any edit under spec/.

  • Contracts without tests don't get built ahead of schedule. generate_spec writes spec/untested-contracts.json (every route/contract with no covering test), and a second PreToolUse hook blocks writes to anything on that list — the same enforcement shape as the spec/-edit block, closing a gap that used to be advisory only.

A PostToolUse hook runs the visible test suite after every edit.

rebuild-dossier demo

Quick start

Available on npm:

npx rebuild-dossier@latest --help    # pull the MCP server (stdio), or:
npm install -g rebuild-dossier        # install the CLI globally

Requires Node 20.12+ (set in package.json engines). To run from source instead, clone the repo, npm install, and use npm start.

Then add it as an MCP server. In Claude Code, from the project you want to rebuild:

claude mcp add rebuild-dossier -- npx -y rebuild-dossier@latest

(or add this to your ~/.claude.json / project .mcp.json):

{
  "mcpServers": {
    "rebuild-dossier": {
      "command": "npx",
      "args": ["-y", "rebuild-dossier@latest"]
    }
  }
}

Then in a session. The first call, ingest_repo, runs instantly with zero setup: static analysis only, no browser, no Chromium, no LLM call. Run it on any app to confirm the server is alive before committing to the full workflow:

ingest_repo({ path: "/path/to/some-app" })
get_case_queue({ repoPath: "/path/to/some-app", interactive: true })
# ...resolve whatever the queue surfaces...
generate_spec({ repoPath: "/path/to/some-app" })

This writes a clean some-app-rebuild/ sibling directory. cd into it, start a fresh Claude Code session (nothing else should be in scope), and paste the contents of its kickoff-prompt.txt.

If this looks useful, a star helps other developers find it.

Operating guide

The full lifecycle, in order — each step's actual behavior, not just the call signature.

1. Ingest the repo

ingest_repo({ path: "/absolute/path/to/some-app" })

Static analysis only — no LLM call, nothing executed. Parses package.json, route files (Express and Next.js App Router today — see scope), build config (Tailwind/Vite/Next, via AST, never executed), existing tests, and scans for comment/TODO signals plus structural smells (e.g. a hardcoded client-side credential check with no server-side verification — the kind of thing nobody ever comments on, which is exactly why it needs its own detector rather than relying on comments existing). Everything lands in <repo>/.dossier/ — this tool's own scratch state, inside the original repo, never shared or uploaded anywhere. You'll get back a summary:

{
  "routes": 8,
  "existingTests": 0,
  "signals": 3,
  "buildConfig": ["tailwind", "next"],
  "openCases": 3,
  "savedTo": "/absolute/path/to/some-app/.dossier/evidence.json"
}

openCases here already reflects reconciliation — comment/TODO signals and structural smells that didn't auto-resolve become case-queue entries automatically.

If routes comes back 0, check for a monorepoHint field before assuming the app has none — ingest_repo needs to be pointed at the actual app directory, not a monorepo's root wrapper (a package.json with apps/*/packages/* next to it, common with Turborepo/Nx/workspace layouts, including ones that never actually declare a workspaces field). The hint lists real candidate directories found under apps//packages/ so you don't have to hunt for the real app yourself — re-run ingest_repo pointed at one of those instead.

If your client supports MCP elicitation, you can skip the manual re-run entirely: pass interactive: true and, when a monorepo root with candidates is detected, ingest_repo asks which one is the real app and ingests it directly — it never silently guesses on its own, the same way get_case_queue's interactive mode always asks rather than resolving anything without you. Declining, an unsupported client, or an answer that isn't one of the real candidates all fall back to the plain hint above, unchanged.

2. (Optional) Crawl the live site

crawl_site({ url: "http://localhost:3000", repoPath: "/absolute/path/to/some-app" })

Only useful if the app is actually running somewhere. Headless Playwright crawl of reachable routes, emitting progress notifications periodically — long crawls get auto-backgrounded by most MCP clients, and a silent multi-minute call risks being killed as unresponsive without them.

This step is the only one that needs a browser. crawl_site drives headless Chromium, which isn't bundled with the server (including via Smithery), so run npx playwright install chromium once first or the tool will fail. Skip it and the rest of the workflow still works. ingest_repo, resolve_case, and generate_spec need no browser at all.

3. (Optional, but do this before step 4) Flag anything you already know is broken

flag_known_bug({
  repoPath: "/absolute/path/to/some-app",
  description: "The login gate secret check runs entirely client-side and is bypassable"
})

The cheapest, most authoritative signal in the whole system — a direct human statement always outranks inference. It overrides auto-resolve for anything it matches, even if every other signal quietly agrees the behavior looks intentional. Do this before resolving the queue, since it changes what shows up there (and can seed a case entirely on its own, with zero other evidence — see docs/v0-findings.md for why that matters).

Matching is plain token overlap against each open case's file path and claim text, not fuzzy or semantic — so one bug description can match (and auto-resolve) more open cases than you intended if your codebase has several similarly-named components. In the validated example, one bug about "the login gate" matched and closed all three of Madeline's near-duplicate gate components in a single call, before any of them were reviewed individually. resolve_case overwrites a case's decision regardless of its current status, so if that's not what you meant, call it directly on the ones it swept up too broadly — don't assume every case it touched was actually the same decision.

4. Resolve the case queue

get_case_queue({ repoPath: "/absolute/path/to/some-app", interactive: true })

interactive: true walks each open case via MCP elicitation — a real interactive prompt in your client, showing the evidence side by side, if your client supports it. If not (or you're scripting this), resolve cases one at a time instead:

resolve_case({ repoPath: "/absolute/path/to/some-app", id: "case:...", decision: "intentional", note: "..." })

This step doesn't have a shortcut. generate_spec refuses to run while any case is still open, by design — there's no partial or in-progress spec to hand a rebuild agent with caveats; phases 1–2 are literally what produce spec/ in the first place.

5. Generate the spec

generate_spec({ repoPath: "/absolute/path/to/some-app" })

Only callable once the queue is empty. Writes CLAUDE.md, .claude/ (rules, hooks, a spec-auditor subagent, and a verify-against-spec skill — all derived from this project's actual contracts and tests, not boilerplate), spec/ (contracts, locked decisions, test-dependencies.json, untested-contracts.json), and tests/ to a clean sibling some-app-rebuild/ directory — never into the original repo. Two more .claude/ artifacts are generated only when they'd earn their keep: a test-verifier subagent, only if there are held-out tests to guard; a parallel-test-fix workflow, only if the generated tests split into two or more independent clusters (by shared route files) worth fixing concurrently. A small app with a couple of tests covering the same routes — like the validated example above — gets neither; that's not a bug, it's the generator refusing to hand a rebuild agent tooling it has nothing real to do with. This step also runs a real mutation check: it deliberately breaks the original code (flips a comparison, drops a null check, off-by-ones a loop bound) in a scratch copy and confirms each generated test actually catches it — anything that doesn't gets moved to tests/weak/ instead of shipped as if it were trustworthy. You'll get back:

{
  "outputDir": "/absolute/path/to/some-app-rebuild",
  "mutationsChecked": 8,
  "weakTests": [],
  "unrunnableTests": []
}

Both weakTests and unrunnableTests land in the same tests/weak/ directory instead of tests/visible/, but for different reasons worth telling apart: a weak test ran fine and just never caught anything a mutation broke; an unrunnable test never passed even against the original, unmutated code (a broken import, a missing environment variable, infrastructure the bare repo doesn't have) — before this distinction existed, an unrunnable test looked indistinguishable from a 100%-effective one, since it "fails" identically whether or not the code under test was mutated. Neither is an error — it's the tool telling you honestly that a specific test didn't earn its place in tests/visible/, and why.

If every generated test lands in tests/weak/ with mutationsChecked: 0, check for a warning field before assuming something's structurally wrong — the far more common cause is that the target repo hasn't had npm install run in it, so the mutation-check scratch copy has none of the target's own real dependencies (next, @prisma/client, whatever the app actually needs) and every generated test fails to even import them. generate_spec checks for this directly and says so, rather than leaving you to debug a confusing all-unrunnable result.

Optional: vision-assisted page-content classification

For a Next.js target, page routes get real Playwright-captured tests (a screenshot plus DOM-text assertions) alongside the API-route tests described above. Whether a piece of captured text gets an exact-match assertion (static) or a loose shape check (dynamic) is decided by a small regex classifier by default — reliable most of the time, but confirmed capable of getting it backwards in both directions on a real app (a hardcoded dropdown legend read as live data; a live, comma-formatted database count read as fixed).

Setting both GROQ_API_KEY and REBUILD_DOSSIER_ENABLE_VISION_CLASSIFICATION=1 before calling generate_spec sends each captured page's screenshot and (secret-redacted) source code to a Groq vision model instead, which can see where a value actually comes from — a literal array in the source vs. a fetch/useState call — rather than only guessing from what the rendered string looks like. Both variables are required together on purpose: an ambient GROQ_API_KEY left over from some unrelated tool must never silently start sending this target repo's code to a third party. Neither variable set (the default) means zero behavior change and zero network calls beyond what generate_spec already does.

This is real added cost, not free: one Groq API call per captured page, plus a deliberate ~20s pacing delay between pages (Groq's free tier has a tight per-minute token budget, and firing requests back to back exhausts it fast) — generate_spec's own response states the exact added time for that run. A page that can't be classified this way for any reason (rate limit, network issue, an invalid response) falls back to the regex classifier for that page only, reported in pageVisionFallbacks — never a silent gap or a failed run. Groq's free tier (no credit card required, at console.groq.com) is enough to try this.

6. Hand it off

cd /absolute/path/to/some-app-rebuild
claude   # or oh-my-pi, opencode — any coding agent, a genuinely fresh session

Paste the contents of kickoff-prompt.txt verbatim. Nothing else should be in that session's context — the directory is fully self-contained on purpose (see How it works), so there's nothing else for a rebuild agent to read, drift toward, or edit in place instead of building cleanly. Read docs/v0-findings.md for what actually happens when you do this against a real app, including exactly where it got stuck.

Connecting from other tools (oh-my-pi, opencode, etc.)

Two ways to run this, both entirely local — there is no hosted/shared instance, and none is required:

stdio (default) — each tool spawns its own copy of the server as a local subprocess. This is the standard way every MCP client (Claude Code, oh-my-pi, opencode) adds a local MCP server — point it at npx tsx src/index.ts (or a built node dist/index.js) from this repo's directory. No extra setup, no auth, nothing in this section applies.

HTTP (optional) — one persistent server on localhost that multiple tools/sessions connect to instead of each spawning their own. Useful if you want oh-my-pi and opencode (or several Claude Code sessions) sharing one running instance. Still fully local — MCP_ALLOWED_HOSTS only needs to include the hostname you'll actually connect to (localhost), not a real domain, unless you deliberately choose to expose this beyond your own machine.

npm run build
PORT=8080 \
MCP_AUTH_TOKEN=$(openssl rand -hex 32) \
MCP_ALLOWED_HOSTS=localhost,127.0.0.1 \
REBUILD_DOSSIER_ALLOWED_PATHS=/absolute/path/to/your/projects \
npm run start:http:prod

All three env vars are required — the server refuses to start without them, on purpose: MCP_AUTH_TOKEN gates every /mcp request (bearer auth), MCP_ALLOWED_HOSTS guards against DNS-rebinding, and REBUILD_DOSSIER_ALLOWED_PATHS (comma-separated absolute directories) is the only paths ingest_repo/generate_spec/etc. are allowed to touch — set it to whatever parent directory holds the repos you actually want to rebuild.

oh-my-pi (.omp/mcp.json or ~/.omp/agent/mcp.json):

{
  "mcpServers": {
    "rebuild-dossier": {
      "type": "http",
      "url": "http://localhost:8080/mcp",
      "headers": { "Authorization": "Bearer ${REBUILD_DOSSIER_TOKEN}" }
    }
  }
}

opencode (opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "rebuild-dossier": {
      "type": "remote",
      "url": "http://localhost:8080/mcp",
      "enabled": true,
      "oauth": false,
      "headers": { "Authorization": "Bearer {env:REBUILD_DOSSIER_TOKEN}" }
    }
  }
}

oauth: false disables opencode's automatic OAuth discovery on a 401 — this server only supports the static bearer token above, not a real OAuth flow. Set the referenced env var (REBUILD_DOSSIER_TOKEN in both examples) to the same value as MCP_AUTH_TOKEN above.

Development

npm test        # full suite
npm run typecheck

Small, single-purpose functions; TDD throughout (tests are written before the implementation they cover, including for the reconciliation logic itself — this is a tool that generates tests, so its own correctness matters as much as any feature).

Current scope, and what's deliberately not built yet

v0 is scoped to prove the core loop, not to be feature-complete. Deliberately deferred, and tracked as real backlog rather than silently skipped:

  • Reconciliation on API-shaped ambiguity (a validation rule, an error-response shape) is still genuinely untested — the one differently-shaped real app validated so far (catchandtrade) happened to have zero comment/TODO signals to reconcile, so this specific question has no answer yet either way. See docs/v0-findings.md.

  • Video/screen-recording ingestion and the video-LLM flagged-window review.

  • Original-CLAUDE.md / auto-memory as an evidence source.

  • Live Chrome MCP capture for auth-gated/multi-account flows a headless crawler can't reach.

  • Asset-manifest extraction (binary files copied byte-verbatim + a hash manifest, locked contract tier) — real design exists, not yet built.

  • A mutator that no-ops a handler entirely (the current three — flip comparison, drop null check, off-by-one — can't produce a "this branch never ran" mutant).

See docs/v0-findings.md for the full, honest write-up: the real bugs found and fixed during validation, the comparison across model tiers, and what's still open.

Contributing

Thanks for considering a contribution! This is an academic/research project — changes should align with the design described in the paper. See CONTRIBUTING.md for setup, testing, and PR guidelines. First-timers welcome — look for issues tagged good first issue or open one and ask what's most useful.

License

MIT

⭐ If rebuild-dossier helps you ship cleaner rebuilds, a star helps other developers find it.

Available Tools

6 tools
crawl_siteCrawl siteB

Playwright headless crawl of reachable routes. Emits periodic progress notifications.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesBase URL to crawl
maxPagesNoOptional cap on how many reachable pages to visit. Unset means no limit.
repoPathYesRepo path whose .dossier/ this crawl evidence should be saved under

Output Schema

ParametersJSON Schema
NameRequiredDescription
savedToYes
openCasesYes
routesVisitedYes
routesWithConsoleErrorsYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotency, and destructive hints. The description adds some behavioral detail by noting it runs headless and emits periodic progress notifications, but it does not clarify what side effects the crawl may produce beyond visiting pages, even though readOnlyHint is false and repoPath suggests saving evidence. No contradiction with annotations was found.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two short sentences with no filler, and the core action is front-loaded. It is concise and readable, though it could have used the extra space to provide more usage context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the schema fully documents all parameters and an output schema exists, the core technical details are covered. However, the description alone does not address when to use the tool, what side effects the crawl might have, or how it relates to the sibling tools. It is adequate but has clear gaps for an agent deciding whether to invoke it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already explains url, maxPages, and repoPath. The description does add a small hint that the crawl follows reachable routes from the base URL, but it does not materially improve on the parameter descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the action ('crawl'), the resource ('site'), and the method ('Playwright headless'), and specifies the scope as 'reachable routes.' This distinguishes it from the sibling tools, which perform different operations like ingesting, flagging, or resolving.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to choose this tool over alternatives, no prerequisites, and no exclusions. The intended context is only implied by the word 'crawl,' not explicitly stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

flag_known_bugFlag known bugA

Record a known bug. Always overrides auto-resolve for any case it matches, regardless of other evidence.

ParametersJSON Schema
NameRequiredDescriptionDefault
repoPathYesRepo path whose .dossier/ this known bug belongs to
descriptionYesFree-text description of a known bug, stored verbatim

Output Schema

ParametersJSON Schema
NameRequiredDescription
bugYes
openCasesYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only indicate that this is a non-read-only, non-idempotent mutation. The description adds the crucial non-obvious behavior that a flagged known bug always wins over auto-resolve regardless of evidence. This is valuable context that annotations cannot communicate. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler. The primary action is front-loaded, followed immediately by the single most important behavioral rule. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter write tool, the description covers the action and the essential override behavior, and the schema documents the parameters. An output schema exists, so return-value details are not needed. The only small gap is that when-to-use guidance is implied rather than explicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and both parameters (repoPath and description) are already well documented in the schema. The main description adds no additional parameter semantics, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('Record a known bug') and immediately supplies the core differentiator: it overrides auto-resolve. This distinguishes it from sibling resolution/auto-resolve tools without needing to inspect the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The second sentence gives a clear behavioral context: use this when a known bug should supersede any auto-resolve conclusion, even when other evidence points elsewhere. It does not explicitly list when not to use it or name sibling tools, but the precedence rule strongly implies the intended usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

generate_specGenerate specA
Destructive

Write CLAUDE.md, .claude/, spec/, tests/, and kickoff-prompt.txt to -rebuild/. Only callable once the case queue is empty. Optional: if the target is a Next.js app with page routes, set GROQ_API_KEY and REBUILD_DOSSIER_ENABLE_VISION_CLASSIFICATION=1 before calling this tool to enable vision-assisted page-content classification (sends each captured page's screenshot and source code to Groq to judge static vs. dynamic content more accurately than plain regex matching) — ask the user for a Groq API key if they want more reliable generated page tests and this isn't already configured. Off by default; nothing changes if unset. Optional: pass authStorageStatePath to reach auth-gated pages during capture — see that field's own description for how to produce it.

ParametersJSON Schema
NameRequiredDescriptionDefault
repoPathYesRepo path that was ingested; output is written to a sibling <repoPath>-rebuild/ directory
authStorageStatePathNoOptional path to a Playwright storageState JSON file (cookies/localStorage from an already-authenticated session against the target app) — load it once with `npx playwright open <url> --save-storage=state.json` after logging in by hand, or any equivalent one-time export. When set, page capture uses it to reach auth-gated pages instead of only ever seeing a login screen; this tool never logs in itself or handles credentials. The file is copied into the rebuild output (tests/fixtures/auth-storage-state.json, gitignored) so generated page tests can reach the same pages when run standalone.

Output Schema

ParametersJSON Schema
NameRequiredDescription
warningNo
outputDirYes
weakTestsYes
skippedPagesYes
capturedPagesYes
pageCaptureNoteNo
unrunnableTestsYes
mutationsCheckedYes
pageVisionFallbacksNo
pageVisionFallbackNoteNo
visionClassificationNoteNo
visionClassificationEnabledYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations already marking this as destructive and non-read-only, the description adds substantial behavioral context: the tool is only callable with an empty case queue, the vision mode is off by default and changes nothing when unset, the tool never logs in or handles credentials itself, and the auth state file is copied into build output and gitignored. These details meaningfully extend beyond the annotation hints and help an agent predict side effects and prerequisites.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action, then moves from precondition to optional enhancements in a logical order. Every sentence carries operational weight: the initial write target, the queue precondition, the vision-mode toggle and tradeoff, and the auth-state option. Although it is longer than a one-liner, the length is justified by the conditional behavior it must convey.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description, annotations, and rich schema collectively cover prerequisites, optional configurations, credential handling, side-effect locations, and output scope. Since an output schema exists, the description does not need to detail return values. There is no obvious gap an agent would need to guess about in order to call this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the input schema already fully documents repoPath and authStorageStatePath. The tool description adds only a cross-reference to authStorageStatePath and an optional storage-state usage note, but does not go beyond what the schema fields themselves say. With high schema coverage, baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: it writes CLAUDE.md, .claude/, spec/, tests/, and kickoff-prompt.txt to a <repo>-rebuild/ directory. This clearly distinguishes it from sibling tools like ingest_repo or crawl_site, which perform other pipeline stages. The title alone would be vague, but the description removes all ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states an explicit precondition: 'Only callable once the case queue is empty,' which tells the agent when it may and may not be invoked. It also provides conditional guidance for two optional modes: when to set the vision-classification env vars, when to ask the user for a Groq key, and when to pass authStorageStatePath. This is direct, operational usage guidance rather than left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_case_queueGet case queueB
Destructive

Return unresolved ambiguity cases from reconciliation.

ParametersJSON Schema
NameRequiredDescriptionDefault
repoPathYesRepo path whose .dossier/ case queue to read
interactiveNoWhen true, walk open cases via MCP elicitation instead of just listing them

Output Schema

ParametersJSON Schema
NameRequiredDescription
openYes
casesYes

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate destructiveHint=true and readOnlyHint=false, but the description's 'Return...' reads as a safe read operation and adds no context about side effects, what may be destroyed, or why the tool is marked destructive. This mismatch makes the safety profile confusing and under-disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is one short sentence with no filler. It front-loads the core purpose, and every word contributes to understanding what the tool returns.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The schema covers parameters and an output schema exists, so return structure is not the description's burden. However, the description is too thin to fully explain the disruptive destructive hint, the reconciliation context, or when an agent should prefer resolve_case, leaving the overall guidance minimally viable but gapped.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so repoPath and interactive are already documented in the schema. The description adds no extra parameter meaning beyond the schema and does not address the interactive behavior or its consequences.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'Return unresolved ambiguity cases from reconciliation' uses a specific verb and resource, making the tool's main output clear. It is distinguishable from siblings like resolve_case, but it does not explicitly call out that distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description only implies when to use the tool: when unresolved ambiguity cases from reconciliation need to be retrieved. It gives no guidance about alternatives such as resolve_case, nor any exclusions, leaving the agent to infer selection criteria from the name and schema.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ingest_repoIngest repoA
Idempotent

Parse package.json, tailwind/vite config, route files, and existing tests via static analysis. No LLM call.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesAbsolute path to the repo to ingest
interactiveNoWhen true and 0 routes are found at a monorepo-shaped path, ask via elicitation which candidate directory is the real app, then ingest that instead

Output Schema

ParametersJSON Schema
NameRequiredDescription
routesYes
savedToYes
signalsYes
openCasesYes
buildConfigYes
monorepoHintNo
existingTestsYes
resolvedMonorepoChoiceNo

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide idempotentHint=true and destructiveHint=false. The description adds meaningful behavioral context with 'static analysis' and 'No LLM call', signaling deterministic, non-LLM execution beyond what annotations state.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler. The first states the operation and scope, and the second adds a key behavioral constraint. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is low complexity, has full schema coverage, an output schema, and annotations covering idempotency and destructiveness. The description supplies the remaining essential facts: what files are parsed and that no LLM call is made.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both path and interactive are already well documented in the input schema. The description does not add parameter-specific meaning, which is acceptable given the schema already carries the burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb, 'Parse', and names concrete resources: package.json, tailwind/vite config, route files, and existing tests. An agent can tell what the tool operates on, though it does not explicitly contrast itself with siblings like generate_spec or crawl_site.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The static-analysis phrasing and 'No LLM call' imply this is a deterministic, lower-cost ingestion step, but the description does not explicitly say when to use this tool versus alternatives. Sibling names provide context, yet no direct routing or exclusion guidance is given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

resolve_caseResolve caseA
DestructiveIdempotent

Resolve one open case with a human decision. Always available, no elicitation capability required.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesThe case id to resolve, as returned by get_case_queue (e.g. "case:...")
noteNoOptional free-text note explaining the decision
decisionYesFree-text decision, e.g. "intentional" or "bug" — stored verbatim, not a fixed enum
repoPathYesRepo path whose .dossier/ this case belongs to

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
statusYes
signalsYes
conflictNo
topicKeyYes
humanDecisionNo
autoResolutionNo
relatedCaseIdsNo
matchedKnownBugsYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already carry the safety profile (destructiveHint=true, idempotentHint=true), and the description adds the useful operational trait that the tool is always available and requires no elicitation capability. It does not, however, disclose what resolution actually changes (e.g., case status or removal from the queue), leaving the side effect only implied by the destructive hint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two short sentences, front-loaded with the primary purpose and followed by a concise availability note. Every word earns its place; there is no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool benefits from rich annotations, 100% parameter documentation, and an output schema, so the description need not explain return values. Still, it omits the practical effect of resolving a case (e.g., the case disappearing from get_case_queue) and provides no guidance about when to prefer this over the closely related sibling flag_known_bug, leaving a small but real completeness gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the baseline is 3. The description adds the key semantic that the decision must be a human decision, which is not stated in the schema's decision property text and helps prevent an agent from fabricating a decision on its own. This one meaningful addition justifies a score above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'resolve one open case' with the key qualifier 'with a human decision.' It is not a tautology and clearly outlines the core action, but it does not explicitly contrast with sibling tools like flag_known_bug or get_case_queue, so it falls short of full differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'Always available, no elicitation capability required' gives some operational context about when the tool can be invoked, implying it is the standard path for resolving a case. However, it never names alternatives or conditions when another sibling should be used instead, so guidance is mostly implicit rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 6 tool updatesv0.2.6-paper
    • Changedcrawl_site2 fields changed
      • addedInput schema / properties / maxPages / description
        Added value: +"Optional cap on how many reachable pages to visit. Unset means no limit."
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "openCases": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "routesVisited": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "routesWithConsoleErrors": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "savedTo": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "routesVisited",
        +    "routesWithConsoleErrors",
        +    "openCases",
        +    "savedTo"
        +  ],
        +  "type": "object"
        +}
    • Changedflag_known_bug1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "bug": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "description": {
        +          "type": "string"
        +        },
        +        "flaggedAt": {
        +          "type": "string"
        +        },
        +        "id": {
        +          "type": "string"
        +        },
        +        "matchHints": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "required": [
        +        "id",
        +        "description",
        +        "matchHints",
        +        "flaggedAt"
        +      ],
        +      "type": "object"
        +    },
        +    "openCases": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "bug",
        +    "openCases"
        +  ],
        +  "type": "object"
        +}
    • Changedgenerate_spec1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "capturedPages": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "mutationsChecked": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "outputDir": {
        +      "type": "string"
        +    },
        +    "pageCaptureNote": {
        +      "type": "string"
        +    },
        +    "pageVisionFallbackNote": {
        +      "type": "string"
        +    },
        +    "pageVisionFallbacks": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "reason": {
        +            "type": "string"
        +          },
        +          "routeFile": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "routeFile",
        +          "reason"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "skippedPages": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "reason": {
        +            "type": "string"
        +          },
        +          "routeFile": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "routeFile",
        +          "reason"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "unrunnableTests": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "visionClassificationEnabled": {
        +      "type": "boolean"
        +    },
        +    "visionClassificationNote": {
        +      "type": "string"
        +    },
        +    "warning": {
        +      "type": "string"
        +    },
        +    "weakTests": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "outputDir",
        +    "mutationsChecked",
        +    "weakTests",
        +    "unrunnableTests",
        +    "capturedPages",
        +    "skippedPages",
        +    "visionClassificationEnabled"
        +  ],
        +  "type": "object"
        +}
    • Changedget_case_queue1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "cases": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "autoResolution": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "decision": {
        +                "enum": [
        +                  "intentional",
        +                  "bug"
        +                ],
        +                "type": "string"
        +              },
        +              "reason": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "decision",
        +              "reason"
        +            ],
        +            "type": "object"
        +          },
        +          "conflict": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "detail": {
        +                "type": "string"
        +              },
        +              "kind": {
        +                "enum": [
        +                  "known_bug_vs_intentional_evidence",
        +                  "signal_disagreement"
        +                ],
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "kind",
        +              "detail"
        +            ],
        +            "type": "object"
        +          },
        +          "humanDecision": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "decidedAt": {
        +                "type": "string"
        +              },
        +              "decision": {
        +                "type": "string"
        +              },
        +              "note": {
        +                "type": "string"
        +              },
        +              "via": {
        +                "enum": [
        +                  "elicitation",
        +                  "resolve_case_tool"
        +                ],
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "decision",
        +              "decidedAt",
        +              "via"
        +            ],
        +            "type": "object"
        +          },
        +          "id": {
        +            "type": "string"
        +          },
        +          "matchedKnownBugs": {
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "relatedCaseIds": {
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "signals": {
        +            "items": {
        +              "additionalProperties": false,
        +              "properties": {
        +                "affirmativeIntent": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "confidence": {
        +                      "maximum": 1,
        +                      "minimum": 0,
        +                      "type": "number"
        +                    },
        +                    "kind": {
        +                      "enum": [
        +                        "comment",
        +                        "docstring",
        +                        "todo",
        +                        "fixme"
        +                      ],
        +                      "type": "string"
        +                    },
        +                    "locator": {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "endLine": {
        +                          "maximum": 9007199254740991,
        +                          "minimum": -9007199254740991,
        +                          "type": "integer"
        +                        },
        +                        "file": {
        +                          "type": "string"
        +                        },
        +                        "startLine": {
        +                          "maximum": 9007199254740991,
        +                          "minimum": -9007199254740991,
        +                          "type": "integer"
        +                        }
        +                      },
        +                      "required": [
        +                        "file",
        +                        "startLine",
        +                        "endLine"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "text": {
        +                      "type": "string"
        +                    }
        +                  },
        +                  "required": [
        +                    "kind",
        +                    "text",
        +                    "locator",
        +                    "confidence"
        +                  ],
        +                  "type": "object"
        +                },
        +                "claim": {
        +                  "type": "string"
        +                },
        +                "detectedAt": {
        +                  "type": "string"
        +                },
        +                "evidenceText": {
        +                  "type": "string"
        +                },
        +                "id": {
        +                  "type": "string"
        +                },
        +                "locator": {
        +                  "anyOf": [
        +                    {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "endLine": {
        +                          "maximum": 9007199254740991,
        +                          "minimum": -9007199254740991,
        +                          "type": "integer"
        +                        },
        +                        "file": {
        +                          "type": "string"
        +                        },
        +                        "startLine": {
        +                          "maximum": 9007199254740991,
        +                          "minimum": -9007199254740991,
        +                          "type": "integer"
        +                        }
        +                      },
        +                      "required": [
        +                        "file",
        +                        "startLine",
        +                        "endLine"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    {
        +                      "additionalProperties": false,
        +                      "properties": {
        +                        "method": {
        +                          "type": "string"
        +                        },
        +                        "path": {
        +                          "type": "string"
        +                        }
        +                      },
        +                      "required": [
        +                        "path"
        +                      ],
        +                      "type": "object"
        +                    }
        +                  ]
        +                },
        +                "source": {
        +                  "enum": [
        +                    "ingest",
        +                    "crawl",
        +                    "known_bug"
        +                  ],
        +                  "type": "string"
        +                },
        +                "topicKey": {
        +                  "type": "string"
        +                }
        +              },
        +              "required": [
        +                "id",
        +                "source",
        +                "locator",
        +                "topicKey",
        +                "claim",
        +                "evidenceText",
        +                "detectedAt"
        +              ],
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "status": {
        +            "enum": [
        +              "auto_resolved",
        +              "open",
        +              "resolved_by_human"
        +            ],
        +            "type": "string"
        +          },
        +          "topicKey": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "topicKey",
        +          "signals",
        +          "matchedKnownBugs",
        +          "status"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "open": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "open",
        +    "cases"
        +  ],
        +  "type": "object"
        +}
    • Changedingest_repo1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "buildConfig": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "existingTests": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "monorepoHint": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "candidates": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        },
        +        "message": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "message",
        +        "candidates"
        +      ],
        +      "type": "object"
        +    },
        +    "openCases": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "resolvedMonorepoChoice": {
        +      "type": "string"
        +    },
        +    "routes": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "savedTo": {
        +      "type": "string"
        +    },
        +    "signals": {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "routes",
        +    "existingTests",
        +    "signals",
        +    "buildConfig",
        +    "openCases",
        +    "savedTo"
        +  ],
        +  "type": "object"
        +}
    • Changedresolve_case4 fields changed
      • addedInput schema / properties / decision / description
        Added value: +"Free-text decision, e.g. \"intentional\" or \"bug\" — stored verbatim, not a fixed enum"
      • addedInput schema / properties / id / description
        Added value: +"The case id to resolve, as returned by get_case_queue (e.g. \"case:...\")"
      • addedInput schema / properties / note / description
        Added value: +"Optional free-text note explaining the decision"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "https://json-schema.org/draft/2020-12/schema",
        +  "additionalProperties": false,
        +  "properties": {
        +    "autoResolution": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "decision": {
        +          "enum": [
        +            "intentional",
        +            "bug"
        +          ],
        +          "type": "string"
        +        },
        +        "reason": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "decision",
        +        "reason"
        +      ],
        +      "type": "object"
        +    },
        +    "conflict": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "detail": {
        +          "type": "string"
        +        },
        +        "kind": {
        +          "enum": [
        +            "known_bug_vs_intentional_evidence",
        +            "signal_disagreement"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "kind",
        +        "detail"
        +      ],
        +      "type": "object"
        +    },
        +    "humanDecision": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "decidedAt": {
        +          "type": "string"
        +        },
        +        "decision": {
        +          "type": "string"
        +        },
        +        "note": {
        +          "type": "string"
        +        },
        +        "via": {
        +          "enum": [
        +            "elicitation",
        +            "resolve_case_tool"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "decision",
        +        "decidedAt",
        +        "via"
        +      ],
        +      "type": "object"
        +    },
        +    "id": {
        +      "type": "string"
        +    },
        +    "matchedKnownBugs": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "relatedCaseIds": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "signals": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "affirmativeIntent": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "confidence": {
        +                "maximum": 1,
        +                "minimum": 0,
        +                "type": "number"
        +              },
        +              "kind": {
        +                "enum": [
        +                  "comment",
        +                  "docstring",
        +                  "todo",
        +                  "fixme"
        +                ],
        +                "type": "string"
        +              },
        +              "locator": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "endLine": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "file": {
        +                    "type": "string"
        +                  },
        +                  "startLine": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "file",
        +                  "startLine",
        +                  "endLine"
        +                ],
        +                "type": "object"
        +              },
        +              "text": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "kind",
        +              "text",
        +              "locator",
        +              "confidence"
        +            ],
        +            "type": "object"
        +          },
        +          "claim": {
        +            "type": "string"
        +          },
        +          "detectedAt": {
        +            "type": "string"
        +          },
        +          "evidenceText": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "type": "string"
        +          },
        +          "locator": {
        +            "anyOf": [
        +              {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "endLine": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  },
        +                  "file": {
        +                    "type": "string"
        +                  },
        +                  "startLine": {
        +                    "maximum": 9007199254740991,
        +                    "minimum": -9007199254740991,
        +                    "type": "integer"
        +                  }
        +                },
        +                "required": [
        +                  "file",
        +                  "startLine",
        +                  "endLine"
        +                ],
        +                "type": "object"
        +              },
        +              {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "method": {
        +                    "type": "string"
        +                  },
        +                  "path": {
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "path"
        +                ],
        +                "type": "object"
        +              }
        +            ]
        +          },
        +          "source": {
        +            "enum": [
        +              "ingest",
        +              "crawl",
        +              "known_bug"
        +            ],
        +            "type": "string"
        +          },
        +          "topicKey": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "source",
        +          "locator",
        +          "topicKey",
        +          "claim",
        +          "evidenceText",
        +          "detectedAt"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "status": {
        +      "enum": [
        +        "auto_resolved",
        +        "open",
        +        "resolved_by_human"
        +      ],
        +      "type": "string"
        +    },
        +    "topicKey": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "topicKey",
        +    "signals",
        +    "matchedKnownBugs",
        +    "status"
        +  ],
        +  "type": "object"
        +}
  2. 1 tool updatev0.2.2-paper
    • Changedgenerate_spec1 field changed
      • addedInput schema / properties / authStorageStatePath
        Added value: +{
        +  "description": "Optional path to a Playwright storageState JSON file (cookies/localStorage from an already-authenticated session against the target app) — load it once with `npx playwright open <url> --save-storage=state.json` after logging in by hand, or any equivalent one-time export. When set, page capture uses it to reach auth-gated pages instead of only ever seeing a login screen; this tool never logs in itself or handles credentials. The file is copied into the rebuild output (tests/fixtures/auth-storage-state.json, gitignored) so generated page tests can reach the same pages when run standalone.",
        +  "type": "string"
        +}
  3. 6 tool updatesv0.2.0
    • First observedcrawl_site
    • First observedflag_known_bug
    • First observedgenerate_spec
    • First observedget_case_queue
    • First observedingest_repo
    • First observedresolve_case

TDQS

A4/5.0
Disambiguation5/5

Each tool has a clearly distinct role in the pipeline: static repo ingestion, dynamic site crawling, recording a known bug override, listing unresolved cases, resolving a case, and generating the final dossier. There is no functional overlap or ambiguity between tool boundaries.

Naming Consistency5/5

All six tool names follow the same snake_case verb_noun convention, such as ingest_repo, crawl_site, get_case_queue, and generate_spec. The verb choices are specific and the object naming is consistent, making the set predictable and easy to navigate.

Tool Count5/5

Six tools is a well-scoped size for this workflow, covering ingestion, crawling, bug flagging, case management, and final generation without redundancy. Each tool maps to a necessary step in the rebuild-dossier process and fits comfortably within the ideal range.

Completeness4/5

The main workflow is well covered: static analysis, dynamic crawling, human-in-the-loop case resolution, and final spec generation are all present. A minor gap is that there is no tool to list or remove previously flagged known bugs, but this does not prevent completing the core pipeline.

Maintenance

ActivityActive
ResponsivenessWithin a week

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    MCP server that spawns autonomous Claude Code agents in GitHub repos, enabling task delegation with persistent state, multi-step workflows, and job monitoring.
    47
    94
    2
    Apache 2.0
  • F
    license
    A
    quality
    D
    maintenance
    A safe, local MCP server that lets Claude drive a controlled software-development loop (inspect, read, plan, patch, apply, check, analyze, fix, summarize) on a project, using deterministic tools and real diffs/test runs.
    10
    1
    -

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Parker-Fawcett/rebuild-dossier'

If you have feedback or need assistance with the MCP directory API, please join our Discord server