Skip to main content
Glama
Parker-Fawcett

rebuild-dossier

rebuild-dossier

DOI

기존 앱에서 신뢰할 수 있는 재구축 스펙(rebuild spec) — 잠긴 CLAUDE.md, .claude/ 설정, 그리고 변이 테스트(mutation-tested)를 거친 테스트 스위트 — 을 역설계하는 MCP 서버로, 어떤 코딩 에이전트든 그 스펙에 맞춰 앱을 깨끗하게 재구축할 수 있게 해줍니다. 추측에 의존하지 않습니다.

이 도구는 앱을 재구축하지 않습니다. 스펙, 계약(contract), 테스트를 생성하며, 코딩 에이전트가 이를 소비하여 별도로 재구축을 수행합니다. 이 경계는 의도적인 것입니다 — 아래 이유 참조.

상태: v0. 핵심 루프는 작동하며, 실제로 지저분한 저장소 하나를 대상으로 종단 간 검증을 마쳤습니다. 두 개의 독립적인 새 에이전트 핸드오프를 두 모델 계층에서 수행했습니다. 정직한 결과(무엇이 깨졌는지 포함)는 docs/v0-findings.md를 읽어보세요.

이유

선행 연구(AgentModernize, arXiv:2605.17535)에 따르면, 재구축 파이프라인은 검증된 피드백 루프가 없으면 0% 의 행동 동등성(behavioral equivalence)을 보이고, 조잡한 피드백 루프가 있어도 9–19% 에 그칩니다. 이 도구의 핵심 가설은 다음과 같습니다: 테스트를 실행하기 전에 인터페이스 계약을 잠그고, 일괄 재생성 대신 한 번에 하나의 테스트만 수행하는 엄격한 재시도 루프를 사용하면 실질적으로 더 나은 결과를 얻을 수 있다.

이러한 파이프라인에서 가장 위험한 부분은 버그를 의도된 동작으로 조용히 검증해버리는 것입니다 — 네 가지 증거 소스가 아무도 이유를 설명하지 않은 채 같은 실수에 조용히 동의할 수 있습니다. 따라서 이 도구의 단 하나의 절대 불가침 규칙은 다음과 같습니다: 모호성을 자동 해소하려면 신호 일치 누군가 실제로 결정했다는 긍정 신호가 모두 필요합니다 (명시된 주석, 버그를 인정하는 TODO, 또는 직접적인 인간의 답변). 조용한 일치만으로 — 코드와 관찰된 동작이 단순히 일치하고 아무도 이유를 설명한 적이 없는 경우 — 항상 질문이 되며, 겉보기 신뢰도가 아무리 높아도 자동 해소가 되지 않습니다.

Related MCP server: reforge-mcp

작동 방식

일반 Claude Code(또는 MCP 호환 클라이언트) 세션 내에서 실행되는 여섯 개의 MCP 도구:

도구

기능

ingest_repo(path)

정적 분석만 수행하며 LLM 호출이 없습니다: 라우트, package.json, 빌드 설정(AST를 통해, 절대 실행하지 않음), 기존 테스트, 그리고 구조적 냄새 탐지기(예: 서버 측 검증이 없는 클라이언트 전용 자격 증명 검사) — 아무도 주석을 달지 않았어도 실제 모호성을 드러냅니다.

crawl_site(url)

도달 가능한 라우트를 헤드리스 Playwright로 크롤링하며, 긴 크롤링이 응답 없음으로 종료되지 않도록 진행 알림을 제공합니다.

flag_known_bug(description)

자유 텍스트로, 그대로 저장됩니다. 일치하는 모든 항목에 대해 자동 해소를 항상 덮어씁니다 — 시스템에서 가장 저렴하고 권위 있는 신호입니다.

get_case_queue() / resolve_case(id, decision)

모호성 큐입니다. 클라이언트가 지원하면 MCP elicitation을 통해 미해결 질문을 표면화합니다. resolve_case는 스크립트 대체 수단으로 항상 사용 가능합니다.

generate_spec()

케이스 큐가 비어 있을 때만 호출할 수 있습니다. CLAUDE.md, .claude/rules/, .claude/settings.json(규율을 기계적으로 강제하는 훅 — 아래 참조), spec/contracts/*.md, tests/visible/ + tests/held-out/, 그리고 kickoff-prompt.txt를 깨끗한 형제 <repo>-rebuild/ 디렉토리에 작성합니다 — 원본 저장소에는 절대 쓰지 않습니다. 테스트를 확정하기 전에 실제 변이 검사를 실행합니다: 원본 코드를 의도적으로 깨뜨려 각 생성된 테스트가 실제로 그 버그를 잡아내는지 확인하고, 잡아내지 못하는 테스트는 등급을 낮춥니다.

글로만 쓰여 있지 않고 기계적으로 강제되는 규칙

두 모델 계층에 걸친 비교 실행 결과, 약한 모델은 CLAUDE.md를 읽고 "현재 실패하는 것만 빌드하고, 일괄 재생성하지 말 것"을 이해한 다음에도 조용히 위반하는 경우가 있음을 발견했습니다 — 그것을 검사하는 것이 없기 때문입니다. 이 도구의 두 가지 규칙은 바로 그 이유로 산문이 아닌 실제 훅으로 강제됩니다:

  • spec/은 잠겨 있습니다. PreToolUse 훅이 spec/ 아래의 모든 편집을 차단합니다.

  • 테스트가 없는 계약은 일정보다 앞서 빌드되지 않습니다. generate_specspec/untested-contracts.json(커버 테스트가 없는 모든 라우트/계약)을 작성하고, 두 번째 PreToolUse 훅이 해당 목록의 항목에 대한 쓰기를 차단합니다 — spec/-편집 차단과 동일한 강제 형태로, 이전에는 권고 사항에 불과했던 격차를 해소합니다.

PostToolUse 훅은 모든 편집 후에 표시 테스트 스위트를 실행합니다.

빠른 시작

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

Claude Code(또는 MCP 호환 클라이언트)에서 MCP 서버로 추가한 다음, 세션에서:

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

이렇게 하면 깨끗한 some-app-rebuild/ 형제 디렉토리가 생성됩니다. 그 디렉토리로 cd하여 새로운 Claude Code 세션을 시작하고(다른 것은 범위에 없어야 함), 해당 디렉토리의 kickoff-prompt.txt 내용을 붙여넣으세요.

운영 가이드

전체 수명 주기를 순서대로 설명합니다 — 각 단계의 실제 동작을 호출 시그니처가 아닌 실제로 보여줍니다.

1. 저장소 수집

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

정적 분석만 수행합니다 — LLM 호출 없음, 실행되는 것 없음. package.json, 라우트 파일(현재 Express 및 Next.js App Router — 범위 참조), 빌드 설정(Tailwind/Vite/Next, AST를 통해, 절대 실행하지 않음), 기존 테스트를 파싱하고, 주석/TODO 신호와 구조적 냄새(예: 서버 측 검증이 없는 하드코딩된 클라이언트 측 자격 증명 검사 — 아무도 주석을 달지 않는 종류의 것, 그래서 주석이 존재하는 것에 의존하는 대신 자체 탐지기가 필요한 이유)를 스캔합니다. 모든 것은 <repo>/.dossier/에 저장됩니다 — 이 도구 자체의 스크래치 상태로, 원본 저장소 내부에 있으며, 어디에도 공유되거나 업로드되지 않습니다. 요약이 반환됩니다:

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

여기서 openCases는 이미 조정(reconciliation)을 반영합니다 — 자동 해소되지 않은 주석/TODO 신호와 구조적 냄새는 자동으로 케이스 큐 항목이 됩니다.

routes0으로 반환되면 앱에 라우트가 없다고 가정하기 전에 monorepoHint 필드를 확인하세요 — ingest_repo는 모노레포의 루트 래퍼가 아닌 실제 앱 디렉토리를 가리켜야 합니다 (apps/*/packages/*가 옆에 있는 package.json, Turborepo/Nx/워크스페이스 레이아웃에서 흔하며, 실제로 workspaces 필드를 선언하지 않는 경우도 포함). 힌트는 apps//packages/ 아래에서 발견된 실제 후보 디렉토리를 나열하므로 직접 실제 앱을 찾을 필요가 없습니다 — 그 중 하나를 가리켜 ingest_repo를 다시 실행하세요.

클라이언트가 MCP elicitation을 지원하면 수동 재실행을 건너뛸 수 있습니다: interactive: true를 전달하면, 후보가 있는 모노레포 루트가 감지될 때 ingest_repo가 어느 것이 실제 앱인지 묻고 직접 수집합니다 — get_case_queue의 대화형 모드가 사용자 없이 아무것도 해소하지 않는 것과 마찬가지로, 절대 조용히 스스로 추측하지 않습니다. 거부하거나, 지원되지 않는 클라이언트이거나, 실제 후보 중 하나가 아닌 답변은 모두 위의 일반 힌트로 그대로 대체됩니다.

2. (선택 사항) 라이브 사이트 크롤링

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

앱이 실제로 어딘가에서 실행 중인 경우에만 유용합니다. 도달 가능한 라우트를 헤드리스 Playwright로 크롤링하며, 주기적으로 진행 알림을 발행합니다 — 긴 크롤링은 대부분의 MCP 클라이언트에서 자동으로 백그라운드 처리되며, 알림이 없으면 수 분간 조용한 호출이 응답 없음으로 종료될 위험이 있습니다.

3. (선택 사항이지만 4단계 전에 수행) 이미 알고 있는 버그 표시

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

전체 시스템에서 가장 저렴하고 권위 있는 신호입니다 — 직접적인 인간의 진술은 항상 추론보다 우선합니다. 일치하는 모든 항목에 대해 자동 해소를 덮어씁니다, 다른 모든 신호가 그 동작이 의도적으로 보인다고 조용히 동의하더라도. 큐를 해소하기 전에 이 작업을 수행하세요. 큐에 표시되는 내용이 바뀌기 때문입니다(그리고 다른 증거 없이 단독으로 케이스를 생성할 수도 있습니다 — 왜 중요한지는 docs/v0-findings.md 참조).

일치는 각 미해결 케이스의 파일 경로와 주장 텍스트에 대한 단순 토큰 중첩이며, 퍼지 또는 의미론적이 아닙니다 — 따라서 코드베이스에 이름이 유사한 여러 컴포넌트가 있으면 하나의 버그 설명이 의도한 것보다 더 많은 미해결 케이스와 일치(및 자동 해소)할 수 있습니다. 검증된 예에서 "로그인 게이트"에 대한 하나의 버그가 Madeline의 거의 중복된 게이트 컴포넌트 세 개 모두를 단일 호출로 일치시키고 닫았으며, 각각을 개별적으로 검토하기 전이었습니다. resolve_case는 현재 상태와 관계없이 케이스의 결정을 덮어쓰므로, 의도한 바가 아니라면 너무 광범위하게 휩쓸린 케이스에 직접 호출하세요 — 접촉한 모든 케이스가 실제로 동일한 결정이라고 가정하지 마세요.

4. 케이스 큐 해소

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

interactive: true는 MCP elicitation을 통해 각 미해결 케이스를 순회합니다 — 클라이언트가 지원하면 실제 대화형 프롬프트로, 증거를 나란히 보여줍니다. 지원하지 않거나(또는 스크립트로 처리하는 경우) 케이스를 한 번에 하나씩 해소하세요:

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

이 단계에는 지름길이 없습니다. generate_spec은 설계상 케이스가 하나라도 열려 있으면 실행을 거부합니다 — 주의 사항이 있는 부분적 또는 진행 중인 스펙을 재구축 에이전트에게 넘겨줄 수 없습니다. 1–2단계가 바로 spec/을 생성하는 단계입니다.

5. 스펙 생성

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

큐가 비워진 후에만 호출할 수 있습니다. CLAUDE.md, .claude/(규칙, 훅, spec-auditor 서브에이전트, verify-against-spec 스킬 — 모두 프로젝트의 실제 계약과 테스트에서 파생된 것이지, 보일러플레이트가 아님), spec/(계약, 잠긴 결정, test-dependencies.json, untested-contracts.json), 그리고 tests/를 깨끗한 형제 디렉터리 some-app-rebuild/에 기록합니다 — 절대 원본 저장소에는 기록하지 않습니다. 두 개의 추가 .claude/ 산출물은 가치가 있을 때만 생성됩니다: test-verifier 서브에이전트는 보류된 테스트가 있어 지켜야 할 때만, parallel-test-fix 워크플로우는 생성된 테스트가 두 개 이상의 독립적인 클러스터(공유 라우트 파일 기준)로 나뉘어 동시에 수정할 가치가 있을 때만 생성됩니다. 위에서 검증된 예시처럼 동일한 라우트를 다루는 몇 개의 테스트가 있는 작은 앱은 둘 다 얻지 못합니다. 그것은 버그가 아니라, 생성기가 리빌드 에이전트에게 실제로 관련이 없는 도구를 넘겨주기를 거부하는 것입니다. 이 단계는 또한 실제 돌연변이 검사를 실행합니다: 스크래치 복사본에서 원본 코드를 의도적으로 깨뜨리고(비교 연산 뒤집기, null 검사 제거, 루프 경계 off-by-one) 각 생성된 테스트가 실제로 그 돌연변이를 잡아내는지 확인합니다 — 잡아내지 못하는 것은 신뢰할 수 있는 것처럼 배포되는 대신 tests/weak/로 이동합니다. 다음을 돌려받게 됩니다:

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

weakTestsunrunnableTests는 둘 다 tests/visible/ 대신 같은 tests/weak/ 디렉터리에 들어가지만, 그 이유는 구분할 가치가 있습니다: 약한 테스트는 정상적으로 실행되었지만 돌연변이가 깨뜨린 것을 한 번도 잡아내지 못한 테스트이고, 실행 불가능한 테스트는 원본(돌연변이되지 않은) 코드에 대해서조차 통과하지 못한 테스트입니다(깨진 import, 누락된 환경 변수, 빈 저장소에 없는 인프라). 이 구분이 생기기 전에는 실행 불가능한 테스트가 100% 효과적인 테스트와 구별할 수 없어 보였습니다. 테스트 대상 코드가 돌연변이되었는지 여부와 무관하게 동일하게 "실패"하기 때문입니다. 둘 다 오류가 아닙니다 — 특정 테스트가 tests/visible/에 들어갈 자격을 얻지 못했다는 것과 그 이유를 도구가 정직하게 알려주는 것입니다.

모든 생성된 테스트가 mutationsChecked: 0인 채로 tests/weak/에 들어간다면, 구조적으로 뭔가 잘못되었다고 가정하기 전에 warning 필드를 확인하세요 — 훨씬 더 흔한 원인은 대상 저장소에서 npm install이 실행되지 않아 돌연변이 검사 스크래치 복사본에 대상의 실제 의존성(next, @prisma/client, 앱이 실제로 필요로 하는 것)이 하나도 없어서 생성된 모든 테스트가 import조차 실패하는 경우입니다. generate_spec는 이를 직접 확인하고 알려줍니다. 혼란스러운 all-unrunnable 결과를 디버깅하도록 내버려 두지 않습니다.

선택 사항: 비전 기반 페이지 콘텐츠 분류

Next.js 대상의 경우 페이지 라우트는 위에서 설명한 API 라우트 테스트와 함께 실제 Playwright 캡처 테스트(스크린샷 + DOM 텍스트 검증)를 얻습니다. 캡처된 텍스트 조각이 정확 일치 검증(static)을 받을지 느슨한 형태 검사(dynamic)를 받을지는 기본적으로 작은 정규식 분류기가 결정합니다 — 대부분의 경우 신뢰할 수 있지만, 실제 앱에서 양방향 모두 틀릴 수 있음이 확인되었습니다(하드코딩된 드롭다운 범례를 실시간 데이터로 읽거나, 실시간 쉼표 형식 데이터베이스 카운트를 고정된 값으로 읽는 경우).

generate_spec를 호출하기 전에 둘 다 GROQ_API_KEYREBUILD_DOSSIER_ENABLE_VISION_CLASSIFICATION=1을 설정하면 각 캡처된 페이지의 스크린샷과 (비밀번호가 삭제된) 소스 코드를 대신 Groq 비전 모델로 보냅니다. 이 모델은 값이 실제로 어디서 오는지 볼 수 있습니다 — 소스의 리터럴 배열인지 fetch/useState 호출인지 — 렌더링된 문자열의 모양만 보고 추측하는 대신에 말입니다. 두 변수를 의도적으로 함께 요구합니다: 관련 없는 도구에서 남은 환경 변수 GROQ_API_KEY가 조용히 이 대상 저장소의 코드를 제3자에게 보내기 시작해서는 안 됩니다. 어느 변수도 설정하지 않으면(기본값) generate_spec가 이미 하는 것 이상의 동작 변화와 네트워크 호출이 전혀 없습니다.

이것은 공짜가 아니라 실제 추가 비용입니다: 캡처된 페이지당 Groq API 호출 한 번, 그리고 페이지 간 의도적인 ~20초 간격 지연(Groq의 무료 티어는 분당 토큰 예산이 빠듯해서 연속 요청을 보내면 금방 소진됩니다) — generate_spec의 응답 자체에 해당 실행의 정확한 추가 시간이 명시됩니다. 어떤 이유로든(속도 제한, 네트워크 문제, 유효하지 않은 응답) 이 방식으로 분류할 수 없는 페이지는 해당 페이지에 대해서만 정규식 분류기로 폴백되며, pageVisionFallbacks에 보고됩니다 — 조용한 누락이나 실패한 실행은 절대 없습니다. Groq의 무료 티어(신용카드 불필요, console.groq.com)로 이 기능을 시도해 볼 수 있습니다.

6. 인계하기

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

kickoff-prompt.txt의 내용을 그대로 붙여넣으세요. 해당 세션의 컨텍스트에는 다른 것이 없어야 합니다 — 디렉터리는 의도적으로 완전히 자족적이므로(작동 방식 참조), 리빌드 에이전트가 읽을 다른 것이나, 표류할 대상, 깨끗하게 빌드하는 대신 제자리에서 편집할 것이 없습니다. 실제 앱에 대해 이 작업을 수행할 때 실제로 어떤 일이 일어나는지, 정확히 어디서 막혔는지를 포함하여 docs/v0-findings.md를 읽으세요.

다른 도구에서 연결하기 (oh-my-pi, opencode 등)

이것을 실행하는 두 가지 방법이 있으며, 둘 다 완전히 로컬입니다 — 호스팅/공유 인스턴스는 없으며, 필요하지도 않습니다:

stdio (기본값) — 각 도구가 서버의 자체 복사본을 로컬 하위 프로세스로 생성합니다. 이것은 모든 MCP 클라이언트(Claude Code, oh-my-pi, opencode)가 로컬 MCP 서버를 추가하는 표준 방식입니다 — 이 저장소의 디렉터리에서 npx tsx src/index.ts(또는 빌드된 node dist/index.js)를 가리키면 됩니다. 추가 설정, 인증, 이 섹션의 어떤 것도 필요하지 않습니다.

HTTP (선택 사항) — 여러 도구/세션이 각자 생성하는 대신 연결하는 localhost의 하나의 영구 서버입니다. oh-my-pi와 opencode(또는 여러 Claude Code 세션)가 하나의 실행 중인 인스턴스를 공유하려는 경우 유용합니다. 여전히 완전히 로컬입니다 — MCP_ALLOWED_HOSTS는 실제로 연결할 호스트 이름(localhost)만 포함하면 되며, 실제 도메인은 필요하지 않습니다. 의도적으로 이 기능을 자신의 머신 너머로 노출하기로 선택하지 않는 한 말입니다.

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

세 가지 환경 변수는 모두 필수입니다 — 서버는 의도적으로 그것들 없이는 시작을 거부합니다: MCP_AUTH_TOKEN은 모든 /mcp 요청을 게이트합니다(베어러 인증), MCP_ALLOWED_HOSTS는 DNS-리바인딩을 방지하고, REBUILD_DOSSIER_ALLOWED_PATHS(쉼표로 구분된 절대 디렉터리)는 ingest_repo/generate_spec 등이 접근할 수 있는 유일한 경로입니다 — 실제로 리빌드하려는 저장소가 있는 상위 디렉터리로 설정하세요.

oh-my-pi (.omp/mcp.json 또는 ~/.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: false401에서 opencode의 자동 OAuth 검색을 비활성화합니다 — 이 서버는 위의 정적 베어러 토큰만 지원하며 실제 OAuth 흐름은 지원하지 않습니다. 참조된 환경 변수(두 예시 모두에서 REBUILD_DOSSIER_TOKEN)를 위의 MCP_AUTH_TOKEN과 같은 값으로 설정하세요.

개발

npm test        # full suite
npm run typecheck

작고 단일 목적의 함수; 전 과정에 걸쳐 TDD(구현을 다루는 테스트가 구현보다 먼저 작성됩니다. 조정 로직 자체에 대한 테스트도 포함 — 이것은 테스트를 생성하는 도구이므로, 자체적인 정확성은 어떤 기능만큼이나 중요합니다).

현재 범위와 의도적으로 아직 구축되지 않은 것

v0은 기능 완성을 목표로 하지 않고 핵심 루프를 증명하는 데 범위가 정해져 있습니다. 의도적으로 연기되었으며, 조용히 건너뛰는 대신 실제 백로그로 추적됩니다:

  • API 형태의 모호성(검증 규칙, 오류 응답 형태)에 대한 조정은 여전히 실제로 테스트되지 않았습니다 — 지금까지 검증된 유일한 다른 형태의 실제 앱(catchandtrade)은 우연히 조정할 주석/TODO 신호가 전혀 없어서, 이 특정 질문은 어느 쪽으로든 아직 답이 없습니다. docs/v0-findings.md를 참조하세요.

  • 비디오/화면 녹화 수집 및 비디오-LLM 플래그된 창 검토.

  • 원본-CLAUDE.md / 자동 메모리를 증거 소스로 사용.

  • 헤드리스 크롤러가 도달할 수 없는 인증 게이트/다중 계정 흐름을 위한 라이브 Chrome MCP 캡처.

  • 에셋 매니페스트 추출(바이너리 파일을 바이트 단위 그대로 복사 + 해시 매니페스트, 잠긴 계약 티어) — 실제 설계는 존재하지만 아직 구축되지 않음.

  • 핸들러를 완전히 no-op으로 만드는 뮤테이터(현재 세 가지 — 비교 뒤집기, null 검사 제거, off-by-one — 는 "이 분기가 실행된 적 없음" 돌연변이를 만들 수 없음).

전체적이고 정직한 기록은 docs/v0-findings.md를 참조하세요: 검증 중에 발견되고 수정된 실제 버그, 모델 티어 간 비교, 그리고 여전히 열려 있는 사항들.

라이선스

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