TÁNDEM MCP Server
by semaes111
README.md
# TÁNDEM
Refinamiento cruzado entre dos LLM — **Claude Code CLI × Codex CLI** — que trabajan en paralelo sobre copias aisladas del mismo material, se critican mutuamente **con evidencia re-ejecutada**, absorben cada uno lo mejor del otro y solo convergen cuando se cumple un **predicado de excelencia computable** (gates verdes + doble APPROVE + puntuación mínima).
Este repositorio implementa la arquitectura descrita en `tandemarquitectura.md` (proyecto *LLM COLLAB*). Las referencias `§N` de los comentarios del código apuntan a las secciones de ese documento.
---
## 1. Estado actual: esqueleto + base técnica
| Módulo | Fichero(s) | Estado |
|---|---|---|
| Protocolo de mensajes (§5) | `src/protocol/schemas.ts` | ✅ Completo: schemas zod de Finding, Critique, WorkResult, TaskSpec, EvidenceReport, TandemConfig, WorkPackage, ReviseInput, Rebuttal + `parseAgentJson` (extracción y auto-reparación de JSON) |
| Plantillas de prompt (§10) | `src/protocol/prompts/*.md` + `prompts.ts` | ✅ Las 6 plantillas (spec-sync, produce, critique, revise, merge, audit) + motor de renderizado con bloques condicionales |
| Máquina de estados (§3) | `src/orchestrator/state-machine.ts` | ✅ Fases, transiciones legales validadas, estado del run, helpers de ronda |
| Controlador de convergencia (§6) | `src/orchestrator/convergence.ts` | ✅ `checkConvergence` + `isStagnant` con lógica real y tests (incluye anti-adulación) |
| Ejecución de ronda (§3–§4) | `src/orchestrator/round.ts` | ✅ Generalizada PRODUCE\|REVISE ∥ → snapshots git → gates → crítica cruzada ∥ → adjudicación; cancelación del hermano si un agente cae; test de integración sobre repo git real |
| **Bucle completo (Fase 2)** | `src/orchestrator/loop.ts` | ✅ SPEC_SYNC negociado (proponer→fusionar→votar, 2 intentos→ESCALATE) · bucle multironda con CHECK · REBUTTAL con contra-evidencia re-ejecutada · MERGE con integrador rotatorio · FINAL_AUDIT por el que NO integró · una corrección acotada · DELIVER copy-out · kill-switch cooperativo |
| Adaptadores (§7) | `src/adapters/` | ✅ `produce()`/`critique()`/`revise()` + `ask()` genérico validado en ambos. Claude: stdin + auto-reparación con `--resume` + sesión encadenada entre rondas. Codex: `exec -` + `--output-schema`. Modelos configurables por agente |
| Workspace Manager (§9) | `src/workspace/` | ✅ copy-in + repo interno + worktrees (A/B/merge) + install por worktree + `deliver` copy-out (sin `.git` ni `node_modules`) |
| Evidence Runner (§8) | `src/evidence/` | ✅ `runGates` + adjudicación de findings + **adjudicación de contra-evidencia** (REBUTTAL, semántica inversa); rúbrica/links (modo docs) — **Fase 3** |
| Informes | `src/orchestrator/report.ts` | ✅ Por ronda (comparativo) + **final multironda**: tabla de rondas, fusión y auditoría, backlog no bloqueante de minors, mapa de discrepancias si ESCALATE |
| Persistencia (§9) | `src/store/` | ✅ SQLite (runs/rounds/messages + history para resume) + transcript JSONL append-only, alimentados en vivo |
| CLI (§12) | `src/index.ts` | ✅ COMPLETO: `run` (bucle entero) · `status` · `report` · `stop` (sentinela) · `resume` (frontera de ronda o directo a MERGE) · `doctor` |
| **Cabina MCP — Variante B (§14)** | `src/mcp/server.ts` + `mcp/server.ts` | ✅ Servidor MCP stdio para Claude Desktop: 7 tools (`tandem_start/status/report/stop/resume/list/doctor`), runs en segundo plano, testeado con cliente MCP real. Setup: `mcp/README.md` |
| **Modo docs funcional** | `src/evidence/validators/docs-structure.ts` | ✅ Gate mecánico de memorias vía `tandem.docs.json`: cobertura LITERAL del baremo, secciones en espejo, anticontaminación (términos vetados), límites de extensión, cero «rojos», ficheros exigidos; + `links` locales |
| **Eje de entornos** | `src/workspace/agent-env.ts` | ✅ `agentEnv: personal` (cada cuenta con su arsenal — duelo de EQUIPOS; cada modelo interpreta sus skills a su manera, declarándolo en NOTES) \| `clean` (solo auth — duelo de MODELOS); manifiesto `arsenal.json` por run; `sharedTools` MCP idénticas a ambos CLIs (metro común) |
| **Verticales** | `src/verticals.ts` + `verticals/` | ✅ Arquitecturas especializadas como DATOS (config + normas + plantillas), kernel ciego al dominio. Primero: **licitaciones** (método NextHorizont: espejo del baremo, anclaje literal, anticontaminación) — `--vertical licitaciones` |
| Ejecución compartida | `src/execute.ts` | ✅ `executeLoop` + `buildResumeState` comunes a CLI y MCP (logger inyectable; store SIEMPRE por import dinámico) |
| Dashboard / MCP (§12, §14) | `dashboard/`, `mcp/` | 🔲 Placeholders con diseño — **Fase 3** |
Leyenda: ✅ implementado y testeado · 🟡 parcial (lo indicado pendiente) · 🔲 diseñado, sin código.
---
## 2. Requisitos
1. **Node ≥ 20** (probado con Node 22).
2. **pnpm** (`corepack enable` o https://pnpm.io/installation).
3. **git** en el PATH (los worktrees son el mecanismo de aislamiento).
4. **Claude Code CLI** con login de tu suscripción (`claude` en el PATH).
5. **Codex CLI** con `codex login` de tu suscripción ChatGPT.
Los CLIs solo hacen falta para ejecutar runs reales; para desarrollar y testear el orquestador no se necesitan.
---
## 3. Puesta en marcha, paso a paso
```bash
# 1) Entra en la carpeta del proyecto
cd tandem
# 2) Instala dependencias (siempre pnpm, nunca npm)
pnpm install
# 3) Comprueba que el esqueleto compila con TypeScript estricto
pnpm typecheck
# 4) Ejecuta la batería de tests (convergencia, máquina de estados, protocolo)
pnpm test
# 5) Diagnóstico del entorno: qué CLIs tienes y cuáles faltan
pnpm dev doctor
# 6) DUELO COMPLETO (Fase 2): bucle entero hasta la entrega auditada
pnpm dev run --dir ..\mi-carpeta --task "Tarea concreta y verificable"
#
# Fases (cada ronda tarda MINUTOS — §16.1):
# SPEC_SYNC (pactan la spec) → PRODUCE ∥ → gates → crítica cruzada
# → adjudicación → REBUTTAL (contra-evidencia) → CHECK
# → [REVISE con polinización cruzada → …]* hasta MERGE o ESCALATE
# → fusión dirigida (integrador rotatorio) → FINAL_AUDIT (el otro)
# → entrega en runs/<id>/final (o --out <carpeta>)
#
# Flags útiles:
# --blind crítica sin autoría (Solución 1/2)
# --no-spec-sync usar la tarea literal como spec
# --no-rebuttal sin fase de contra-evidencia
# --integrator claude|codex|auto
# --model-claude X · --model-codex Y
# --max-rounds 4 · --threshold 90 · --out D:\resultado
# 7) Control del run en vuelo (desde otra terminal)
pnpm dev status <run-id> # rondas, gates, scores, decisiones
pnpm dev stop <run-id> # kill-switch: para en la próxima frontera de fase
pnpm dev resume <run-id> # reanuda desde la última ronda persistida
pnpm dev report <run-id> # imprime el informe final
```
Notas: ambos CLIs deben tener **login hecho** (`claude` y `codex login`); tu carpeta original **nunca se toca** (copy-in → todo pasa en `runs/<id>/`, y la entrega es copy-out); `resume` re-produce la ronda que estaba en vuelo sobre los worktrees existentes.
---
## 4. Estructura del repositorio (§11)
```
tandem/
├── package.json # pnpm · Node ≥ 20 · ESM · TypeScript estricto (sin `any`)
├── tsconfig.json
├── src/
│ ├── index.ts # CLI (commander): run · status · report · resume · doctor · stop
│ ├── orchestrator/
│ │ ├── state-machine.ts # fases y transiciones (§3)
│ │ ├── round.ts # ejecución de una ronda (§3–§4) [Fase 1]
│ │ └── convergence.ts # checkConvergence + isStagnant (§6)
│ ├── adapters/
│ │ ├── agent-adapter.ts # interfaz común + AgentContext (§7)
│ │ ├── claude-code.ts # claude -p / --resume (headless)
│ │ └── codex.ts # codex exec / resume / --output-schema (headless)
│ ├── protocol/
│ │ ├── schemas.ts # zod: TODOS los mensajes agente↔orquestador (§5)
│ │ ├── prompts.ts # carga y renderizado de plantillas
│ │ └── prompts/ # spec-sync · produce · critique · revise · merge · audit (§10)
│ ├── workspace/
│ │ ├── git.ts # helpers git (repo interno del run)
│ │ ├── worktrees.ts # ws-A / ws-B / ws-merge (§9)
│ │ ├── diff.ts # snapshots etiquetados r<N>-A/B y diffs
│ │ └── merge.ts # entrega fast-forward / copy-out [Fase 2]
│ ├── evidence/
│ │ ├── runner.ts # runGates + replayEvidence (el árbitro no-LLM, §8)
│ │ └── validators/ # typecheck · lint · tests · build · rubric · links
│ └── store/
│ ├── db.ts # SQLite: runs · rounds · messages (coste/latencia)
│ └── transcript.ts # JSONL append-only auditable
├── test/ # vitest: convergencia · máquina de estados · protocolo
├── dashboard/ # Fase 3 (Next.js, Server Components sobre la SQLite)
└── mcp/ # Fase 3 (variante B: cabina de mando en Claude Desktop)
```
---
## 5. Decisiones técnicas ya cerradas en el esqueleto
1. **ESM + NodeNext**: imports con extensión `.js` obligatoria. TypeScript en modo máxima estrictez (`strict`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`); el tipo `any` está prohibido.
2. **El APPROVE nunca contradice la evidencia**: implementado en `convergence.ts` (no confiado al modelo) y testeado en `test/convergence.test.ts` (caso "ANTI-ADULACIÓN").
3. **Sin checks aplicables no hay pase gratis**: `runGates` devuelve `pass=false` si ningún validador aplica — obliga a configurar gates o rúbrica antes de que nada pueda aprobarse.
4. **Un finding sin evidencia no existe**: `FindingSchema` exige `evidence` no vacía; la re-ejecución (`replayEvidence`) la adjudica en Fase 1.
5. **Codex valida en origen, Claude en destino**: Codex usa `--output-schema` (JSON conforme garantizado); para Claude, `parseAgentJson` + bucle de auto-reparación sobre la misma sesión (máx. 2 intentos).
6. **Identidad git local por run**: el repo interno usa `tandem-orchestrator <tandem@localhost>` — no toca tu configuración global.
7. **Línea de comandos fija + datos por stdin** (`src/util/exec.ts`): los CLIs se invocan con `shell: true` (imprescindible para los shims `.cmd` de Windows) pero el prompt NUNCA se interpola en la línea de comandos — viaja por stdin (`claude -p` y `codex exec -`). Cero problemas de escapado en cmd.exe y sh.
8. **Heurística de adjudicación documentada** (`src/evidence/runner.ts`): buscadores (grep/rg) reproducen con exit 0; comandos normales con exit ≠ 0 o si la salida contiene la expectativa declarada tras `→`; citas si el fichero:línea existe. Los `disputed` no cuentan (§5) pero quedan en el informe y el transcript.
9. **La identidad de las críticas la normaliza el orquestador**: author/target/round se sobreescriben tras el parseo — un agente no puede atribuirse la autoría que quiera (testeado).
10. **REBUTTAL con semántica inversa**: la contra-evidencia del autor gana si su comando TIENE ÉXITO (exit 0 o expectativa presente) — al revés que un finding, donde el fallo demuestra el defecto. Contra-evidencia no ejecutable = finding mantenido (se exige comando, no prosa).
11. **SPEC_SYNC en tres pasos deterministas**: proponer ∥ → fusiona uno → vota el otro; si rechaza, fusiona el que rechazó (con sus objeciones sobre la mesa) y vota el primero; segundo rechazo → ESCALATE `spec_conflict`. Barato de escalar en ronda 0, caro en ronda 4 (§3).
12. **Kill-switch cooperativo**: `tandem stop` crea el sentinela `STOP`; el bucle lo consulta entre fases (los CLIs en vuelo no se matan a mitad). `resume` retoma en frontera de ronda re-produciendo la ronda en vuelo sobre los worktrees existentes.
13. **Cancelación del hermano**: si un agente cae en una fase paralela, el otro se aborta vía AbortSignal → no quedan procesos huérfanos consumiendo cuota.
14. **Normas del duelo (Karpathy Guidelines adaptadas)**: los cuatro principios de [multica-ai/andrej-karpathy-skills](https://github.com/multica-ai/andrej-karpathy-skills) (MIT) — pensar antes de programar, simplicidad primero, cambios quirúrgicos, ejecución guiada por objetivos — se inyectan automáticamente en los prompts en DOS caras: `norms-build.md` para quien produce/revisa/fusiona y `norms-review.md` para quien critica/audita (los incumplimientos objetivos son material legítimo de finding, sin relajar la evidencia obligatoria ni habilitar bloqueos por estilo). Adaptación clave: el "pregunta si dudas" headless se canaliza a supuestos declarados en `NOTES.md` y ambigüedades resueltas en SPEC_SYNC. Se desactivan pasando `NORMS: null` a `buildPrompt` (o editando los .md).
---
## 6. Roadmap — qué implementar y en qué orden
**Fase 1 — MVP (una ronda demostrable) — ✅ COMPLETADA** (y validada con un duelo real en producción).
**Fase 2 — Bucle completo — ✅ COMPLETADA** (validada en producción: run `cfa59ae1`, fusión de codex auditada por claude y entregada).
**Variante B — Cabina en Claude Desktop — ✅ COMPLETADA:** servidor MCP local con runs en segundo plano (ver `mcp/README.md`).
**Fase 3 — Confort (pendiente):** dashboard Next.js, modo docs (rúbricas + links), contenedores, deliver fast-forward en modo-rama, sesión persistente de Codex (`exec resume` + eventos `--json`), tabla de rondas del informe reconstruida desde la BD en runs reanudados.
**Fase 3 — Confort:** dashboard Next.js, servidor MCP (variante B), modo docs (rúbricas + links), `--blind` operativo, presupuestos finos, contenedores.
---
## 7. Solución de problemas (Windows)
**`better-sqlite3` falla al instalar con «"node-gyp" no se reconoce…».**
El proyecto fija `better-sqlite3@^12` a propósito: la v12 instala con `prebuild-install || node-gyp rebuild`, es decir, **descarga un binario ya compilado** para tu plataforma (hay binarios win32-x64 para Node 22 — ABI 127 — y Node 24 — ABI 137) y solo compila como último recurso. La v13 eliminó los binarios precompilados y SIEMPRE compila desde código, lo que en Windows exige Python + Visual Studio Build Tools. Si con la v12 sigue intentando compilar, tu versión de Node no tiene binario publicado: comprueba `node -v` y usa Node 22 o 24 LTS.
**`doctor` decía que un CLI no estaba, pero sí está.** En Windows, `pnpm`/`claude`/`codex` son shims `.cmd`, y Node (tras el parche de seguridad CVE-2024-27980) se niega a spawnearlos sin shell (error EINVAL). El doctor ya los invoca con `shell: true`. Verifica en una terminal nueva que `claude --version` y `codex --version` responden.
**codex aborta con «Not inside a trusted directory».** Es su puerta de confianza: en modo interactivo pregunta si confías en la carpeta; en headless no puede y aborta. TANDEM ya invoca `codex exec` con `--skip-git-repo-check` (seguro: el cwd es siempre el worktree git del run). Si lo ves, tu copia del adaptador es antigua.
**codex escupe errores «failed to load skill … missing YAML frontmatter».** Son NO fatales: codex rechaza skills personales de `~/.agents/skills/` cuyo `SKILL.md` no empieza por `---`, y continúa. Puedes ignorarlos o poner esas skills en cuarentena para limpiar el ruido (muévelas a otra carpeta y reviértelo cuando quieras).
**Runs reales en Windows.** Los CLIs se lanzan con línea de comandos fija + prompt por stdin (ver decisión 7), que funciona en Windows nativo. Si tu instalación de codex no soportara `--sandbox workspace-write` en Windows, la alternativa es ejecutar los runs bajo WSL2.
## 8. Seguridad (§13) — ya reflejada en el esqueleto
- Claude: `--permission-mode acceptEdits` + lista blanca `CLAUDE_ALLOWED_TOOLS` (nunca `bypassPermissions` fuera de contenedor).
- Codex: `--sandbox workspace-write` (escritura limitada al worktree).
- `runs/` está en `.gitignore` (contiene worktrees y transcripts); `.env` fuera del árbol que ven los agentes.
- Timeouts por fase (`phaseTimeoutMs`) y presupuesto por run (`budgetMs`) en la config.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing