Skip to main content
Glama
Parker-Fawcett

rebuild-dossier

rebuild-dossier

DOI

Un servidor MCP que aplica ingeniería inversa a una especificación de reconstrucción confiable — un CLAUDE.md bloqueado, la configuración de .claude/ y una suite de pruebas probadas por mutación — a partir de una aplicación existente, para que cualquier agente de codificación pueda reconstruirla limpiamente según esa especificación en lugar de adivinar.

No reconstruye la aplicación. Produce la especificación, los contratos y las pruebas que un agente de codificación consume para hacerlo por separado. Este límite es deliberado — ver Por qué a continuación.

Estado: v0. El bucle principal funciona y se ha validado de extremo a extremo contra un repositorio real y desordenado, incluyendo dos traspasos independientes de agente nuevo en dos niveles de modelo. Lee docs/v0-findings.md para conocer el resultado honesto, incluido lo que se rompió.

Por qué

Investigaciones previas (AgentModernize, arXiv:2605.17535) encontraron que un pipeline de reconstrucción obtiene un 0% de equivalencia de comportamiento sin un bucle de retroalimentación verificado, y solo un 9–19% con uno aproximado. La apuesta detrás de esta herramienta: fijar los contratos de interfaz antes de ejecutar las pruebas, más un estricto bucle de reintento de una prueba a la vez en lugar de regeneración por lotes, funciona significativamente mejor.

La parte más arriesgada de cualquier pipeline de este tipo es validar silenciosamente un error como intencional: cuatro fuentes de evidencia pueden coincidir en silencio sobre el mismo error sin que nadie haya dicho por qué. Por lo tanto, la única regla innegociable en esta herramienta: resolver automáticamente una ambigüedad requiere tanto la concordancia de señales como una señal afirmativa de que alguien realmente decidió (un comentario explícito, un TODO que admite un error o una respuesta humana directa). El acuerdo silencioso por sí solo — código y comportamiento observado simplemente coincidiendo, sin que nadie haya dicho por qué — siempre se convierte en una pregunta, nunca en una auto-resolución, sin importar cuán alta sea la confianza aparente.

Related MCP server: reforge-mcp

Cómo funciona

Seis herramientas MCP, ejecutadas desde una sesión normal de Claude Code (o cualquier sesión compatible con MCP):

Herramienta

Qué hace

ingest_repo(path)

Solo análisis estático, sin llamada LLM: rutas, package.json, configuración de compilación (mediante AST, nunca ejecutada), pruebas existentes y detectores de olores estructurales (por ejemplo, una verificación de credenciales solo del lado del cliente sin verificación del lado del servidor) que revelan ambigüedad real incluso cuando nadie ha comentado al respecto.

crawl_site(url)

Rastreo headless de Playwright de las rutas accesibles, con notificaciones de progreso para que los rastreos largos no se eliminen por no responder.

flag_known_bug(description)

Texto libre, almacenado textualmente. Siempre anula la auto-resolución para cualquier cosa que coincida: la señal más barata y autoritativa del sistema.

get_case_queue() / resolve_case(id, decision)

La cola de ambigüedades. Expone preguntas abiertas mediante la elicitación MCP cuando el cliente lo admite; resolve_case siempre está disponible como respaldo programado.

generate_spec()

Solo se puede llamar una vez que la cola de casos esté vacía. Escribe CLAUDE.md, .claude/rules/, .claude/settings.json (ganchos que mecánicamente hacen cumplir la disciplina — ver más abajo), spec/contracts/*.md, tests/visible/ + tests/held-out/ y kickoff-prompt.txt en un directorio hermano limpio <repo>-rebuild/ — nunca en el repositorio original. Ejecuta una verificación de mutación real antes de finalizar las pruebas: rompe deliberadamente el código original y confirma que cada prueba generada realmente lo detecta, degradando las que no lo hacen.

Reglas que se aplican mecánicamente, no solo por escrito

Una ejecución comparativa en dos niveles de modelo encontró que un modelo más débil leerá felizmente CLAUDE.md, entenderá "solo construye lo que está fallando actualmente, no regeneres en lotes", y luego lo violará silenciosamente de todos modos — porque nada lo verificaba. Dos reglas en esta herramienta ahora se aplican mediante ganchos reales, no prosa, exactamente por esa razón:

  • spec/ está bloqueado. Un gancho PreToolUse bloquea cualquier edición bajo spec/.

  • Los contratos sin pruebas no se construyen antes de lo previsto. generate_spec escribe spec/untested-contracts.json (cada ruta/contrato sin una prueba que lo cubra), y un segundo gancho PreToolUse bloquea escrituras a cualquier cosa en esa lista — la misma forma de aplicación que el bloqueo de edición de spec/, cerrando una brecha que solía ser solo de asesoramiento.

Un gancho PostToolUse ejecuta la suite de pruebas visible después de cada edición.

Inicio rápido

git clone https://github.com/businessfawcett-cloud/rebuild-dossier.git
cd rebuild-dossier
npm install
npx playwright install chromium   # needed for crawl_site

Agrégalo como servidor MCP en Claude Code (o cualquier cliente compatible con MCP), luego en una sesión:

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" })

Esto escribe un directorio hermano limpio some-app-rebuild/. Haz cd en él, inicia una sesión nueva de Claude Code (nada más debe estar en el alcance) y pega el contenido de su kickoff-prompt.txt.

Guía de operación

El ciclo de vida completo, en orden: el comportamiento real de cada paso, no solo la firma de la llamada.

1. Ingerir el repositorio

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

Solo análisis estático — sin llamada LLM, nada se ejecuta. Analiza package.json, archivos de rutas (Express y Next.js App Router hoy — ver alcance), configuración de compilación (Tailwind/Vite/Next, mediante AST, nunca ejecutada), pruebas existentes, y escanea señales de comentarios/TODO además de olores estructurales (por ejemplo, una verificación de credenciales del lado del cliente codificada sin verificación del lado del servidor — el tipo de cosa que nadie comenta, que es exactamente por qué necesita su propio detector en lugar de depender de que existan comentarios). Todo aterriza en <repo>/.dossier/ — el estado de borrador propio de esta herramienta, dentro del repositorio original, nunca compartido ni subido a ningún lado. Obtendrás un resumen:

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

openCases aquí ya refleja la conciliación: las señales de comentarios/TODO y los olores estructurales que no se auto-resolvieron se convierten automáticamente en entradas de la cola de casos.

Si routes devuelve 0, verifica un campo monorepoHint antes de asumir que la aplicación no tiene ninguna — ingest_repo debe apuntarse al directorio real de la aplicación, no al envoltorio raíz de un monorepo (un package.json con apps/*/packages/* junto a él, común en diseños Turborepo/Nx/workspace, incluidos los que nunca declaran un campo workspaces). La pista lista directorios candidatos reales encontrados bajo apps//packages/ para que no tengas que buscar la aplicación real tú mismo — vuelve a ejecutar ingest_repo apuntando a uno de esos en su lugar.

Si tu cliente admite la elicitación MCP, puedes omitir por completo la re-ejecución manual: pasa interactive: true y, cuando se detecte una raíz de monorepo con candidatos, ingest_repo pregunta cuál es la aplicación real y la ingiere directamente — nunca adivina silenciosamente por su cuenta, de la misma manera que el modo interactivo de get_case_queue siempre pregunta en lugar de resolver algo sin ti. Rechazar, un cliente no compatible o una respuesta que no sea uno de los candidatos reales, todo cae de nuevo a la pista simple anterior, sin cambios.

2. (Opcional) Rastrear el sitio en vivo

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

Solo es útil si la aplicación se está ejecutando en algún lugar. Rastreo headless de Playwright de las rutas accesibles, emitiendo notificaciones de progreso periódicamente — los rastreos largos se ponen en segundo plano automáticamente en la mayoría de los clientes MCP, y una llamada silenciosa de varios minutos corre el riesgo de ser eliminada como no receptiva sin ellas.

3. (Opcional, pero hazlo antes del paso 4) Marca cualquier cosa que ya sepas que está rota

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

La señal más barata y autoritativa de todo el sistema: una declaración humana directa siempre supera a la inferencia. Anula la auto-resolución para cualquier cosa que coincida, incluso si todas las demás señales coinciden silenciosamente en que el comportamiento parece intencional. Haz esto antes de resolver la cola, ya que cambia lo que aparece allí (y puede sembrar un caso por sí solo, con cero otra evidencia — ver docs/v0-findings.md para saber por qué importa).

La coincidencia es superposición de tokens simple contra la ruta de archivo y el texto de reclamo de cada caso abierto, no difusa ni semántica — por lo que una descripción de error puede coincidir (y auto-resolver) más casos abiertos de los que pretendías si tu código tiene varios componentes con nombres similares. En el ejemplo validado, un error sobre "la puerta de inicio de sesión" coincidió y cerró los tres componentes de puerta casi duplicados de Madeline en una sola llamada, antes de que cualquiera de ellos fuera revisado individualmente. resolve_case sobrescribe la decisión de un caso independientemente de su estado actual, así que si eso no es lo que querías, llámalo directamente sobre los que barrió demasiado ampliamente — no asumas que cada caso que tocó era realmente la misma decisión.

4. Resolver la cola de casos

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

interactive: true recorre cada caso abierto mediante la elicitación MCP — un prompt interactivo real en tu cliente, mostrando la evidencia lado a lado, si tu cliente lo admite. Si no (o estás automatizando esto), resuelve los casos uno a la vez en su lugar:

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

Este paso no tiene atajo. generate_spec se niega a ejecutarse mientras haya algún caso abierto, por diseño — no hay una especificación parcial o en progreso para entregar a un agente de reconstrucción con advertencias; las fases 1–2 son literalmente lo que produce spec/ en primer lugar.

5. Generar la especificación

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

Solo se puede llamar una vez que la cola está vacía. Escribe CLAUDE.md, .claude/ (reglas, hooks, un subagente spec-auditor y una habilidad verify-against-spec — todo derivado de los contratos y pruebas reales de este proyecto, no de plantillas), spec/ (contratos, decisiones bloqueadas, test-dependencies.json, untested-contracts.json) y tests/ en un directorio hermano limpio some-app-rebuild/ — nunca en el repositorio original. Se generan dos artefactos más de .claude/ solo cuando valen la pena: un subagente test-verifier, solo si hay pruebas reservadas que proteger; un flujo de trabajo parallel-test-fix, solo si las pruebas generadas se dividen en dos o más clústeres independientes (por archivos de ruta compartidos) que valga la pena corregir en paralelo. Una aplicación pequeña con un par de pruebas que cubren las mismas rutas — como el ejemplo validado anteriormente — no recibe ninguno; eso no es un error, es el generador negándose a entregar a un agente de reconstrucción herramientas con las que no tiene nada que ver realmente. Este paso también ejecuta una verificación de mutaciones real: rompe deliberadamente el código original (invierte una comparación, elimina una comprobación de nulo, desvía un límite de bucle) en una copia de prueba y confirma que cada prueba generada realmente lo detecta — cualquier cosa que no lo haga se mueve a tests/weak/ en lugar de enviarse como si fuera confiable. Recibirás:

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

Tanto weakTests como unrunnableTests terminan en el mismo directorio tests/weak/ en lugar de tests/visible/, pero por razones diferentes que vale la pena distinguir: una prueba débil se ejecutó bien y simplemente nunca detectó nada que una mutación rompiera; una prueba no ejecutable nunca pasó ni siquiera contra el código original sin mutar (una importación rota, una variable de entorno faltante, infraestructura que el repositorio desnudo no tiene) — antes de que existiera esta distinción, una prueba no ejecutable parecía indistinguible de una 100% efectiva, ya que "falla" de manera idéntica tanto si el código bajo prueba fue mutado como si no. Ninguno es un error — es la herramienta diciéndote honestamente que una prueba específica no se ganó su lugar en tests/visible/, y por qué.

Si cada prueba generada termina en tests/weak/ con mutationsChecked: 0, verifica si hay un campo warning antes de asumir que algo está estructuralmente mal — la causa mucho más común es que el repositorio objetivo no ha tenido npm install ejecutado en él, por lo que la copia de verificación de mutaciones no tiene ninguna de las dependencias reales del objetivo (next, @prisma/client, lo que sea que la aplicación necesite) y cada prueba generada falla incluso al importarlas. generate_spec verifica esto directamente y lo dice, en lugar de dejarte depurar un resultado confuso de todo no ejecutable.

Opcional: clasificación de contenido de página asistida por visión

Para un objetivo Next.js, las rutas de página obtienen pruebas reales capturadas con Playwright (una captura de pantalla más aserciones de texto DOM) junto con las pruebas de rutas API descritas anteriormente. Si un fragmento de texto capturado recibe una aserción de coincidencia exacta (static) o una verificación de forma suelta (dynamic) lo decide un pequeño clasificador de expresiones regulares por defecto — confiable la mayoría de las veces, pero confirmado capaz de equivocarse en ambas direcciones en una aplicación real (una leyenda de menú desplegable codificada leída como datos en vivo; un recuento de base de datos en vivo con formato de coma leído como fijo).

Configurar ambas GROQ_API_KEY y REBUILD_DOSSIER_ENABLE_VISION_CLASSIFICATION=1 antes de llamar a generate_spec envía la captura de pantalla de cada página capturada y el código fuente (con secretos redactados) a un modelo de visión de Groq en su lugar, que puede ver de dónde viene realmente un valor — un array literal en el código fuente vs. una llamada fetch/useState — en lugar de solo adivinar por cómo se ve la cadena renderizada. Ambas variables se requieren juntas a propósito: una GROQ_API_KEY ambiental dejada de alguna herramienta no relacionada nunca debe comenzar silenciosamente a enviar el código de este repositorio objetivo a un tercero. Ninguna variable configurada (el valor predeterminado) significa cero cambio de comportamiento y cero llamadas de red más allá de lo que generate_spec ya hace.

Esto es un costo real agregado, no gratis: una llamada a la API de Groq por página capturada, más un retraso deliberado de ~20s entre páginas (el nivel gratuito de Groq tiene un presupuesto de tokens por minuto ajustado, y disparar solicitudes consecutivas lo agota rápido) — la propia respuesta de generate_spec indica el tiempo adicional exacto para esa ejecución. Una página que no se puede clasificar de esta manera por cualquier razón (límite de velocidad, problema de red, respuesta inválida) recurre al clasificador de expresiones regulares solo para esa página, informado en pageVisionFallbacks — nunca un vacío silencioso o una ejecución fallida. El nivel gratuito de Groq (sin tarjeta de crédito requerida, en console.groq.com) es suficiente para probar esto.

6. Entregarlo

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

Pega el contenido de kickoff-prompt.txt textualmente. Nada más debería estar en el contexto de esa sesión — el directorio está completamente autocontenido a propósito (ver Cómo funciona), así que no hay nada más que un agente de reconstrucción pueda leer, desviarse o editar en lugar de construir limpiamente. Lee docs/v0-findings.md para ver qué sucede realmente cuando haces esto contra una aplicación real, incluyendo exactamente dónde se atascó.

Conexión desde otras herramientas (oh-my-pi, opencode, etc.)

Dos formas de ejecutar esto, ambas completamente locales — no hay instancia alojada/compartida, y no se requiere ninguna:

stdio (predeterminado) — cada herramienta genera su propia copia del servidor como un subproceso local. Esta es la forma estándar en que cada cliente MCP (Claude Code, oh-my-pi, opencode) agrega un servidor MCP local — apúntalo a npx tsx src/index.ts (o un node dist/index.js compilado) desde el directorio de este repositorio. Sin configuración adicional, sin autenticación, nada en esta sección aplica.

HTTP (opcional) — un servidor persistente en localhost al que múltiples herramientas/sesiones se conectan en lugar de que cada una genere la suya. Útil si quieres que oh-my-pi y opencode (o varias sesiones de Claude Code) compartan una instancia en ejecución. Sigue siendo completamente local — MCP_ALLOWED_HOSTS solo necesita incluir el nombre de host al que realmente te conectarás (localhost), no un dominio real, a menos que deliberadamente elijas exponer esto más allá de tu propia máquina.

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

Las tres variables de entorno son obligatorias — el servidor se niega a iniciar sin ellas, a propósito: MCP_AUTH_TOKEN protege cada solicitud /mcp (autenticación bearer), MCP_ALLOWED_HOSTS protege contra el rebinding de DNS, y REBUILD_DOSSIER_ALLOWED_PATHS (directorios absolutos separados por comas) es la única ruta que ingest_repo/generate_spec/etc. tienen permitido tocar — configúrala con el directorio padre que contenga los repositorios que realmente quieres reconstruir.

oh-my-pi (.omp/mcp.json o ~/.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 desactiva el descubrimiento automático de OAuth de opencode en un 401 — este servidor solo admite el token bearer estático anterior, no un flujo OAuth real. Configura la variable de entorno referenciada (REBUILD_DOSSIER_TOKEN en ambos ejemplos) con el mismo valor que MCP_AUTH_TOKEN anterior.

Desarrollo

npm test        # full suite
npm run typecheck

Funciones pequeñas y de un solo propósito; TDD en todo (las pruebas se escriben antes de la implementación que cubren, incluida la lógica de reconciliación en sí — esta es una herramienta que genera pruebas, por lo que su propia corrección importa tanto como cualquier característica).

Alcance actual, y lo que deliberadamente no está construido aún

v0 está enfocado en probar el bucle central, no en ser completo en funciones. Diferido deliberadamente, y rastreado como backlog real en lugar de omitido silenciosamente:

  • La reconciliación en la ambigüedad de forma de API (una regla de validación, una forma de respuesta de error) sigue genuinamente sin probar — la única aplicación real de forma diferente validada hasta ahora (catchandtrade) resultó tener cero señales de comentario/TODO para reconciliar, por lo que esta pregunta específica no tiene respuesta aún en ningún sentido. Ver docs/v0-findings.md.

  • Ingestión de video/grabación de pantalla y la revisión de ventanas marcadas por video-LLM.

  • Original-CLAUDE.md / auto-memoria como fuente de evidencia.

  • Captura en vivo de Chrome MCP para flujos con autenticación/multi-cuenta que un rastreador sin cabeza no puede alcanzar.

  • Extracción de manifiesto de activos (archivos binarios copiados byte a byte + un manifiesto hash, nivel de contrato bloqueado) — existe diseño real, aún no construido.

  • Un mutador que no-opere un manejador por completo (los tres actuales — invertir comparación, eliminar comprobación de nulo, desviar por uno — no pueden producir un mutante de "esta rama nunca se ejecutó").

Ver docs/v0-findings.md para el informe completo y honesto: los errores reales encontrados y corregidos durante la validación, la comparación entre niveles de modelos, y lo que aún está abierto.

Licencia

MIT

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