Tus agentes entregan. Tú compruebas. Cotejo se llamó Foco hasta septiembre de 2026: el comando
foco, las variablesFOCO_*, la carpeta~/.config/focoy las tareas con marca^foco-…siguen funcionando.
Cotejo es el tablero de control para hacer vibe coding profesional. Tus agentes escriben el código; Cotejo organiza el proyecto y verifica lo que entregan. No escribe código por ti: lleva el proyecto y comprueba lo que se hizo.
Sirve para que cualquier persona, programe o no, construya software con IA de forma estructurada y que pueda crecer:
- Cada proyecto guarda su contexto, sus decisiones y su arquitectura en una carpeta
.cotejo/dentro de su propio repo, que cualquier agente consulta barato. - Cada tarea va al modelo adecuado: el enrutador decide a quién le toca y por qué.
- Nada se da por hecho sin evidencia y sin tu revisión: el agente entrega con pruebas, y marcar una tarea como hecha es siempre cosa tuya, en CotejoBoard.
Se usa con cualquier agente de terminal (Claude Code, Codex, Antigravity CLI, Gemini CLI, opencode) o con cualquier agente que hable MCP. Es gratis, en Windows y Linux.
Warning
Cotejo 1.2 es software en fase beta. Todavía puede tener fallos o comportarse de forma inesperada. Se ofrece «tal cual», sin garantías de ningún tipo, como dice su licencia (
LICENSE, cláusula 8). Si algo falla, cuéntalo en un issue.
Descargar: la última versión trae el instalador de Windows, el paquete
de Arch y el .tar.gz para otras distribuciones de Linux, con sus SHA256SUMS. O instala con una
línea, como en el paso 1 de abajo.
El código está a la vista, pero no es open source. Cotejo es software propietario de uso
gratuito: puedes leer, revisar y auditar este código, y reportar fallos, pero no copiarlo,
modificarlo ni redistribuirlo (ver LICENSE, cláusulas 2.4 y 3).
Empezar en un repo
Cuatro pasos, de la instalación a la primera tarea comprobada.
1. Instala Cotejo. Una línea, sin clonar nada (el detalle, las opciones y el paquete de Arch están en «Instalar»):
curl -fsSL https://cotejo.dev/install.sh | sh
2. Corre cotejo init en la carpeta del proyecto. Crea el .cotejo/ del repo —tareas.md, proyecto.md y una carpeta por cada tipo de conocimiento: decisiones, arquitectura, problemas, aprendizajes, bitácora, referencias y recursos—, deja el proyecto en la versión 0.1.0 y lo registra en la fuente repo. Si no tenías ninguna fuente que funcione (lo normal en una instalación nueva), la deja activa; si ya usas Obsidian o Notion y funcionan, no te la cambia, y cotejo fuentes usar repo lo hace cuando quieras. Es idempotente: repetirlo no pisa nada.
cd /ruta/al/proyecto
cotejo init # dentro de un repo git
cotejo init --repo ~/mi-app # también sirve para una carpeta nueva o sin git: la crea y le hace git init
3. Pídele a tu agente que arranque el proyecto. Dile «empiezo un proyecto» o «prepara este repo para trabajar con Cotejo». La skill cotejo (skills/cotejo/referencias/inicio.md, se instala con Cotejo) lo entrevista en un solo mensaje de cinco preguntas con valores por defecto y deja escrito el objetivo, el stack y el siguiente paso en proyecto.md, las decisiones que condicionan lo demás como propuestas, una arquitectura inicial y entre 3 y 8 tareas para la 0.1.0. Si el proyecto ya existe en Obsidian o Notion, ver «Traer un proyecto que ya existe».
4. Trabaja las tareas y compruébalas en el board. El agente reparte la 0.1.0 (cotejo plan), toma cada tarea, la hace y la entrega con evidencia: commits, diff y pruebas que Cotejo puede volver a correr. En CotejoBoard aceptas las decisiones propuestas, compruebas lo que se entregó y apruebas. cotejo doctor dice si algo no funciona y qué hacer.
cotejo plan --proyecto mi-app # qué modelo recibiría cada pendiente
cotejo version --proyecto mi-app # en qué versión van y cuántas tareas quedan
cotejo # abre o cierra CotejoBoard
Tus agentes entregan. Tú compruebas.
Para agentes
Cotejo tiene una cara sin interfaz, pensada para que un agente trabaje contra el segundo cerebro sin pagar el arranque de GTK y sin editar el Markdown a mano. Sale todo en JSON por la salida estándar. El comando se llama cotejo; tareas-obsidian es el mismo programa con su nombre de antes, y sigue funcionando.
cotejo tareas --proyecto Cotejo # cuáles faltan (por defecto excluye hechas)
cotejo tareas --proyecto Cotejo --todas # todas, incluyendo hechas
cotejo tareas --proyecto Cotejo --estado hecha # solo hechas
cotejo crear "..." --proyecto Cotejo # anotar trabajo nuevo
cotejo tomar <id> --agente opus # pendiente → haciéndola
cotejo entregar <id> --evidencia "..." # haciéndola → para comprobar
[--prueba "pytest -q"]... [--repo <carpeta>] # + rama, commits, diff y pruebas
cotejo comprobar <id> # vuelve a correr esas pruebas; no escribe nada
cotejo bloquear <id> --motivo "..." # haciéndola → pendiente, sin dueño
cotejo asignar <id> sonnet # cambiar de dueño
cotejo estado # los conteos de siempre
cotejo ahorro # qué costó enterarse por aquí
Y, para lo otro que necesita saber un agente —a quién le toca cada tarea—, los verbos del enrutador:
cotejo plan --proyecto Cotejo --solo-despachables # qué modelo recibiría cada pendiente
cotejo decidir --tarea <id> # a quién le toca esa, y por qué
cotejo despachar <id> # tomarla a nombre de ese modelo
cotejo modelos # el catálogo de niveles y modelos registrados
cotejo revisar # qué pasó con lo que se repartió
cotejo protocolo # el trato entero, para leerlo
cotejo maestro --proyecto Cotejo --cliente claude # abrir un agente que reparte las asignadas
cotejo importar plan plan.md --proyecto Cotejo # qué tareas sacaría; ensayo por defecto
cotejo importar obsidian Cotejo --detalle # qué entradas de .cotejo/ saldrían de la nota; ensayo
cotejo importar notion Cotejo --destino <carpeta> # igual, desde una base de Notion
[--aplicar] # y con esto, las crean de verdad
Y, para el conocimiento del repo que no son tareas —decisiones, arquitectura, problemas,
aprendizajes, bitácora y referencias, cada uno en .cotejo/ (ver «El almacén» más abajo)—:
cotejo contexto # objetivo, tareas, decisiones y problemas vigentes, temas
cotejo buscar --tipo decision --temas auth # una línea por entrada; barato
cotejo leer dec-x7k2 # la entrada completa, con su `version`
cotejo proponer decision --titulo "..." --temas auth --texto "..." # propuesta; la acepta una persona
cotejo anotar problema --titulo "..." --temas ci --texto "..."
cotejo bitacora "qué se hizo hoy"
cotejo editar arq-9f1a --version <hash> --texto "..." # arquitectura, referencia o proyecto.md
cotejo resolver pro-9f3a --solucion "..."
entregar guarda además evidencia que se puede volver a comprobar: si se corre dentro de un repo git (o con --repo <carpeta>), la rama, los commits desde la rama base y el resumen del diff (archivos con sus +/-); y cada --prueba "<comando>" la corre Cotejo mismo, sin shell y con tiempo límite, y anota su argv, el final de su salida y su código de salida. Todo va a bitacora.jsonl junto al texto de --evidencia, en claves que se agregan (git, pruebas, evidencia_esquema). Una prueba en rojo no frena la entrega —puede venir roja de antes—, pero se avisa y queda anotada con su código.
Si la tarea es de un repo de git, despachar le crea por defecto su propio worktree, fuera del repo y del vault, con una rama cotejo/<id>: es donde trabaja y commitea el agente, y de donde entregar saca la evidencia sin que dos tareas del mismo repo se pisen. --sin-aislar (o enrutador.worktrees.aislar: false en la config) vuelve al comportamiento de antes, para una tarea que no toca código o un repo donde no conviene. cotejo worktrees lista dónde quedó cada uno —con --limpiar, retira los que ya sobran (la tarea se aprobó, se devolvió a Pendiente o ya no existe)—; nunca borra una rama ni algo sin commitear. El board retira el de una tarea sola al aprobarla o devolverla.
comprobar <id> lee, no escribe: vuelve a correr —en ese mismo worktree, si lo tiene— las pruebas que anotó la última entrega, con su mismo argv y su mismo tiempo límite, y dice si el resultado sigue igual. Es lo que usa también el botón Comprobar de CotejoBoard; aprobar la tarea sigue siendo de una persona.
importar plan convierte un plan.md en tareas: lee sus casillas - [ ] o, si no hay ninguna, sus encabezados de paso (## Paso N, ### Tarea N), y para cada una propone la dificultad y el modelo igual que decidir. Es un ensayo por defecto —nunca toca el vault sin --aplicar—, y repetirlo no duplica: una tarea que ya existe en el proyecto con el mismo texto sale con "creada": false.
importar obsidian <proyecto> es el ensayo de traer un proyecto del vault a su .cotejo/ (1.2): localiza la nota, sus subnotas (las de su carpeta y las que dicen proyecto: "[[X]]") y los adjuntos que enlazan; resuelve el repo (repo: local, un .git dentro de la carpeta del proyecto, o --destino) y reparte cada sección de la plantilla a su tipo: decisiones y problemas por fila de tabla, aprendizajes por viñeta, la bitácora por ### fecha, las tareas a tareas.md y Objetivo, Stack, Enlaces y Siguiente paso a proyecto.md. Lo que no encaja sale en sin_clasificar con su motivo, y los archivos sueltos que nadie enlaza se cuentan en no_enlazados sin importarse. No escribe nada, ni en el vault ni en el repo.
Con --aplicar escribe ese mismo plan en el .cotejo/ del repo (y le hace git init si --destino no era un repo): las decisiones como aceptada con autor: importado, los adjuntos copiados a recursos/ con su ficha, y los enlaces reescritos —a la nota del proyecto van a [[proyecto]], a una subnota a su referencia y a otra nota del vault quedan como texto con su origen—. Crea la tarea «Revisar lo importado: resúmenes, temas y fichas» y apunta el proyecto en migrados de la fuente obsidian, que desde entonces lo lee del repo. No hace commit y no toca la nota del vault: quitar el proyecto de migrados lo deshace. Repetirlo no duplica nada (cada entrada guarda su origen), y se niega sin escribir si el repo ya tiene otras tareas.
Marcar un proyecto como migrado no apaga el resto del vault: con la fuente obsidian activa, los proyectos de migrados se leen de su repo y todos los demás siguen leyéndose de las notas, los dos a la vez y bajo el mismo --proyecto de siempre (es la fuente obsidian envuelta en tareas/fuentes/compuesta.py, transparente para quien la usa). Mientras dure una migración gradual puede haber tareas en los dos sitios; lo resuelve justamente que cada proyecto cuenta una sola vez, del lado que diga migrados.
importar notion <proyecto> es la misma idea para una base de Notion (1.2 · D3), y más modesta: trae las tareas por el adaptador que ya tengas registrado (mismo formato, a tareas.md) y cada página de la base como una referencia con resumen: pendiente, también con --destino/--aplicar/--detalle y ensayo por defecto. No marca el proyecto como migrado de la fuente Notion —Notion sigue leyéndose igual, sin la fuente compuesta que sí tiene Obsidian—, así que mientras no cambies de fuente puede haber el mismo proyecto en Notion y en su .cotejo/; --destino solo hace falta la primera vez, porque Cotejo recuerda el repo para la siguiente corrida.
bloquear es la salida honesta: la tarea no se puede terminar, vuelve a Pendiente sin dueño y con el motivo a la vista. Sin ese verbo, un agente atascado solo tenía dos salidas y las dos son peores: dejarla en Haciéndola ocupando la columna sin que nadie sepa por qué, o entregarla a medias, que mete en Para comprobar algo que no hay nada que comprobar. El motivo es obligatorio por la misma razón que la evidencia: una tarea que vuelve a Pendiente sin explicación la toma el siguiente agente para estrellarse contra lo mismo.
crear es la contraparte de poder leer lo que falta: sin él, un agente que encuentra trabajo sin anotar solo puede decírselo a quien le esté leyendo, y eso se pierde al cerrar la sesión. La tarea cae con las demás de la nota principal del proyecto —no al final del archivo, donde viven las decisiones—, nace pendiente, sin dueño y con su marca de bloque puesta, porque quien la crea va a querer nombrarla en la llamada siguiente. Repetirlo es seguro: si el proyecto ya tiene una tarea sin terminar que dice exactamente lo mismo, devuelve esa con "cambio": false. --proyecto prefiere el nombre exacto («Cotejo» no es ambiguo aunque exista «Cotejo - Planning para Producción»). No se crea en las carpetas sueltas (Inbox, Diario): no tienen nota principal, y elegir en cuál cae la tarea sería inventarse dónde vive. Crear un proyecto tampoco está: es una nota nueva en el segundo cerebro, y la escribe una persona.
No hay verbo para finalizar, y esa ausencia es el diseño. Si el agente puede marcar hecha su propia tarea, «hecha» deja de significar «alguien la revisó» y pasa a significar «el agente cree que terminó». Marcar [x] se hace en CotejoBoard, con la mano.
Por qué existe esta CLI y no basta con que el agente edite las notas: vault.py comprueba que la línea siga exactamente igual que cuando se leyó antes de escribir, y reemplaza el archivo de forma atómica. Editar por fuera se salta esa verificación, y la forma de fallar es pisar trabajo ajeno en silencio.
Enterarse por aquí es entre 5 y 10 veces más barato que leer las notas: las pendientes de un proyecto son ~480 tokens contra ~4.700 de la nota entera, y las 101 tareas del vault son ~7.300 contra ~36.600. Hay tres tamaños para pedir, y conviene usar el más chico que sirva: estado (~80 tokens) → tareas con filtros → la nota entera, solo si de verdad hace falta el contexto. Ese número ya no hay que creérselo: cotejo ahorro lo mide sobre las llamadas que de verdad se hicieron (ver más abajo).
Cada escritura devuelve la tarea como quedó, para no tener que volver a preguntar, y trae "cambio": false cuando no hizo falta tocar nada — repetir una operación es seguro. Los errores traen salida, que dice qué hacer, y reintentable, que dice si vale la pena repetir:
{"error": "La nota Cotejo.md cambió desde que leíste la tarea",
"salida": "Vuelve a pedir `tareas` y repite la operación con el id nuevo. No se escribió nada.",
"reintentable": true}
El id de una tarea sale de tareas y no se construye a mano. Es la marca de bloque de su línea (cotejo-a1b2), que viaja con la tarea aunque alguien edite la nota por arriba o la mueva de sitio; se acepta con ^ delante, que es como se ve en la nota. Una tarea gana su marca la primera vez que se le escribe, así que las que nadie ha tocado todavía se nombran por su nota y su número de línea, y ese sí se mueve: si el id deja de resolver, el error lo dice y la salida es volver a listar.
Si un id llegara a responder a dos tareas, la operación se niega y las nombra en vez de escribir en la primera que encuentre: pisar la tarea equivocada en silencio es la peor forma de fallar.
tareas y tomar traen además evidencia o motivo cuando la tarea tiene una: lo último que se dijo de ella. En una tarea devuelta eso es el motivo del rechazo, y es lo que hay que leer antes de rehacerla.
Cada operación se anexa a ~/.local/state/tareas-obsidian/bitacora.jsonl, una línea de JSON por cambio (ver más abajo).
Si alguna nota no se pudo leer, la respuesta trae avisos con cuál y por qué. Importa: las tareas de esa nota no están en la lista, y sin el aviso eso se ve igual que una nota sin tareas.
COTEJO_VAULT y COTEJO_CARPETA_PROYECTOS apuntan a otro vault en una sola invocación, sin tocar la config; COTEJO_CARPETAS_SUELTAS (separadas por comas, vacía para apagarlas) hace lo mismo con las carpetas sueltas.
El almacén: el conocimiento del repo
Además de tareas.md, un repo puede llevar en .cotejo/ el resto de lo que no es código pero
informa el desarrollo —decisiones, arquitectura, problemas, aprendizajes, bitácora y
referencias— (1.2 · A1/A2), cada entrada en su propio archivo de Markdown con un frontmatter
mínimo y un id estable (dec-x7k2, pro-9f3a, arq-4m1p…) que no cambia aunque el archivo
se renombre. cotejo init crea el esqueleto entero; qué carpeta le toca a cada tipo está en
«La fuente repo», más abajo.
Para enterarse, de menos a más (B1/B2):
| Verbo | Qué devuelve |
|---|---|
cotejo contexto [--tope N] |
Objetivo, stack y siguiente paso de proyecto.md; tareas por estado; las --tope decisiones y problemas vigentes más recientes (10 por defecto, con el total real); y los temas que existen. Pensado para costar menos de 1k tokens |
cotejo buscar [--tipo] [--temas] [--estado] [--desde] [--texto] [--limite] |
Una línea por entrada (id, tipo, título, resumen): el camino barato para decidir qué vale la pena leer entero |
cotejo leer <id> |
La entrada completa, con su cuerpo y su version (hash); de un recurso, la ruta de su archivo y si existe, nunca el contenido |
Los tres aceptan --repo <carpeta>; por defecto es la raíz git desde donde se llama.
Para escribir (C1-C3):
| Verbo | Qué hace |
|---|---|
cotejo proponer decision --titulo --temas --texto [--reemplaza <dec-id>] [--autor] |
Crea una decisión en propuesta. Con --reemplaza, al crearla deja la vieja en reemplazada |
cotejo anotar <problema|aprendizaje|referencia|arquitectura> --titulo --temas --texto |
Una entrada nueva de ese tipo, con su id |
cotejo anotar arquitectura --titulo --pieza "capa|nombre|frase|tecnología|tareas" |
La arquitectura dibujable: una pieza por --pieza, en las capas ve, hace, guarda o conecta; leer le pone a cada una su estado según sus tareas |
cotejo bitacora "texto" |
Añade al final del archivo del día; nunca reescribe |
cotejo editar <id> --version <hash> --texto |
Cambia el texto de una arquitectura, una referencia o proyecto.md. Se niega si --version no coincide con la que tiene ahora, igual que TareaCambiada con las tareas |
cotejo resolver <pro-id> --solucion "..." |
Problema abierto → resuelto, con la solución que lo cerró |
Toda escritura devuelve la entrada que dejó (id, ruta, version), para no tener que
releerla. Las decisiones no se editan nunca: su texto es fijo y una que ya no aplica se
reemplaza con proponer decision --reemplaza <dec-id>; editar sobre una decisión se niega y
dice eso.
Lo que ningún verbo hace, a propósito: aceptar una decisión (C5). proponer decision la
deja propuesta; pasarla a aceptada es de la persona, y solo desde CotejoBoard —sale como
carta propia en Para comprobar, con la misma vista de revisión que una entrega: su texto y,
si reemplaza otra, la vieja al lado, con el único botón de Aceptar—. Revisar o aprobar una
tarea que propuso una decisión solo avisa que lo hizo,
