Tres agentes de Claude deliberan sobre tu rama antes de que lo haga un humano. Código, tests y documentación. Los tres siempre emiten veredicto: uno solo aprueba el consejo.
GOD'S IN HIS HEAVEN, ALL'S RIGHT WITH THE WORLD.
Demo acelerada ×4 · vídeo completo (48 s)
⚠ Grabada antes del reenfoque: muestra el veto —hoy retirado— y a CASPER como agente de seguridad. Pendiente de regrabar.
MAGI toma el diff de tu rama y el issue de GitHub que dice resolver, y se los entrega a tres
agentes de Claude con roles distintos. Cada uno emite un veredicto. No es un simulador ni un
prototipo con Math.random(): MELCHIOR y CASPER leen tu repositorio de verdad con Read, Grep,
Glob y Bash, y devuelven hallazgos reales. BALTHASAR trabaja a ciegas a propósito —ver más
abajo.
| Agente | Rol | Qué demuestra | |
|---|---|---|---|
| 01 | MELCHIOR |
DEV_AGENT |
Que el cambio es el más corto que resuelve la causa raíz. Caza sobreingeniería, duplicación y archivos saturados: cada línea de más la paga un humano en cada revisión y una IA en cada lectura. |
| 02 | BALTHASAR |
TEST_AGENT |
Que el sistema no es robusto. Trabaja a ciegas —solo ve el issue y los tests, nunca la implementación— y busca el caso que estos tests dejarían pasar. |
| 03 | CASPER |
DOCS_AGENT |
Que los .md concuerdan con lo implementado, para que alguien —humano o IA— entienda el proyecto sin abrir el código. |
Si pudiera leer la implementación acabaría validando que los tests describen el código que se escribió. La pregunta que importa es otra: ¿bastarían estos tests para confiar en cualquier implementación del issue?
El aislamiento es real, no una instrucción en el prompt: recibe el diff filtrado por pathspec de
git a los archivos de test, y Read/Grep/Glob/Bash le llegan por disallowed_tools, que el
SDK retira del contexto del modelo. No puede hacer trampa aunque quiera.
Los tres corren en paralelo y los tres llegan hasta el final. Ningún rechazo cancela a los demás: un dictamen parcial te obliga a repetir la corrida entera, que sale más caro que dejar terminar a los otros dos. Quieres las tres respuestas de una pasada.
flowchart LR
A["issue completo<br/>+ git diff base...HEAD"] --> M["MELCHIOR · 01<br/>diff completo"]
A --> B["BALTHASAR · 02<br/>solo tests"]
A --> C["CASPER · 03<br/>diff completo"]
M --> D{"¿los tres<br/>aprueban?"}
B --> D
C --> D
D -->|"sí"| V["承認 APPROVED"]
D -->|"alguno rechaza"| R["拒否 REJECTED"]
Un agente que se cae, que devuelve JSON roto o que no devuelve veredicto cuenta como rechazo. El sistema falla cerrado: nada se aprueba por un accidente de formato.
中断 ABORTED queda para una sola cosa: el 初期化 RESET del operador.
- Python 3.10+ y
uv - Claude Code autenticado — el SDK usa tus credenciales locales,
no necesitas
ANTHROPIC_API_KEY ghautenticado en el repo que vayas a evaluar (gh auth login)- Linux con
zenityokdialogpara el selector de carpetas
git clone https://github.com/zamax14/MAGI-Agent.git
cd MAGI-Agent
uv sync
uv run magiAbre http://localhost:8000 y:
参照 ···abre el explorador nativo → elige el repositorio a evaluar- Se cargan solas las ramas, la base y la lista de issues abiertos
更新lanza ungit fetch --pruney recarga ramas e issues, sin tocar tu working tree- Elige la rama, el issue y el modelo, y pulsa MAGI
- Los tres paneles parpadean en
照合中 LINKINGy aterrizan en承認o拒否 - Clic en cualquier panel → hallazgos del agente y su
INSTRUCTIONS.mdeditable 初期化 RESETaborta la corrida y devuelve los agentes a待機 STANDBY
Elegir rama hace
git checkoutde verdad. Los agentes leen el working tree conReadyGrep, así que la rama tiene que estar puesta o el diff y los archivos en disco dirían cosas distintas. Por eso MAGI se niega a correr con cambios sin commitear —te lo dice y no toca nada— y devuelve el repo a la rama en la que estabas al terminar, también si pulsasRESET.
RESET mata los procesos de verdad. Cerrar la pestaña no basta: mientras el generador SSE está bloqueado esperando a los agentes, el servidor nunca ve la desconexión y seguirían quemando tokens en segundo plano. El botón los termina explícitamente.
El contexto se arma de forma determinista antes de invocar a nadie. Todo lo que los agentes necesitan ya viene en el prompt, así que no gastan turnos redescubriéndolo:
| Paso | Comando | Resultado |
|---|---|---|
| Rama base | git symbolic-ref refs/remotes/origin/HEAD → main/master |
verifica que el ref exista de verdad |
| Diff | git diff <base>...HEAD |
merge-base, tope de 200 000 chars |
| Issue | gh issue view <n> --json …,labels,comments |
cuerpo, etiquetas y todos los comentarios, tope de 20 000 chars |
El prompt cierra con una orden explícita: no ejecutes gh ni git diff para releer esto. Cada
agente responde con un bloque JSON final que parse_verdict() extrae — se queda con el último
bloque, por si el agente se corrigió a mitad de camino.
MAGI-Agent/
├── magi/
│ ├── repo.py # git, gh y el selector de carpetas — todo lo determinista
│ ├── agents.py # identidad, prompt, Claude Agent SDK y parser de veredictos
│ ├── council.py # paralelismo y cancelación
│ └── server.py # FastAPI: estáticos + SSE, sin base de datos
├── web/
│ ├── index.html # solo marcado
│ ├── magi.css # lienzo, paneles recortados y animaciones
│ └── magi.js # estado, render y SSE — sin framework ni build step
├── agents/
│ ├── melchior.md # INSTRUCTIONS.md editables en caliente
│ ├── balthasar.md
│ └── casper.md
└── test_magi.py
Los agents/*.md son el system prompt de cada agente y se releen en cada corrida: los editas
desde la UI (pestaña 指示書 INSTRUCTIONS.MD), guardas, y la siguiente deliberación ya usa el texto
nuevo. Sin reiniciar nada.
Se elige desde la UI. El default se puede fijar por entorno:
MAGI_MODEL=sonnet uv run magi # opus · sonnet · haikuEs una lista blanca: cualquier otro valor cae al default en lugar de llegar al SDK.
API
| Método | Ruta | Qué hace |
|---|---|---|
GET |
/ |
La UI |
GET |
/api/context?repo=&branch= |
{repo_name, branch, base} — sin branch, la rama actual |
GET |
/api/branches?repo= |
Ramas checkouteables: locales más las de origin sin local |
GET |
/api/issues?repo= |
Issues abiertos para el desplegable |
GET |
/api/pick?start= |
Abre el selector de carpetas nativo, devuelve la ruta absoluta |
POST |
/api/fetch?repo= |
git fetch --prune |
GET |
/api/run?repo=&issue=&model=&branch= |
SSE: un evento por transición de estado |
POST |
/api/cancel |
Mata los agentes en curso y restaura la rama |
GET/PUT |
/api/instructions/{agent_id} |
Lee/escribe el INSTRUCTIONS.md |
/api/run es GET y no POST porque EventSource solo emite peticiones GET.
Los eventos del stream:
En pantallas de 800×480 o menos —una Raspberry Pi con la pantalla oficial de 7", por ejemplo— el tablero cambia a un layout compacto que va 1:1, sin escalar.
No es el tablero de escritorio encogido: a la escala que tocaría (0.448) las etiquetas de 12.5px caerían a 5.6px. En vez de eso, el modo compacto se queda con lo que informa y suelta lo decorativo (los titulares 提訴/決議, el MAGI vertical, el reloj), para que el triángulo MELCHIOR–BALTHASAR–CASPER conserve el alto y el texto su tamaño real.
- Los controles pasan a una fila de objetivos táctiles de 44px de alto.
- La consola va anclada abajo: si el navegador se come alto con su barra, lo que se estrecha es el hueco del triángulo y los controles siguen en pantalla.
- El
参照abre igual el selector nativo, que en táctil es mejor afordancia que teclear la ruta.
El corte está en @media (max-width: 900px), (max-height: 620px) dentro de web/magi.css.
feature ──▶ develop ──▶ master
masteres la rama estable: solo recibe merges desdedevelop.developes la rama de integración y el destino por defecto de cualquier PR.- Las ramas de trabajo salen de
developy se nombrantype/issue-name—fix/logout-hang,feat/selector-de-rama,docs/update-readme.
Los commits siguen Conventional Commits en una sola
línea: type(scope): descripción simple. Si un commit necesita un párrafo para justificarse,
es señal de que hay que partirlo en commits más atómicos, no de que le falte cuerpo.
MAGI usa esto sobre sí mismo: _default_base() resuelve develop como base del diff para
cualquier rama de trabajo, y develop se diffea contra la estable.
uv run --with pytest pytest test_magi.py -qCubren lo que puede fallar en silencio: el parser de veredictos (incluidos JSON roto y veredicto desconocido), el formateo del issue con su tope duro, el filtrado del diff que aísla a BALTHASAR de la implementación, la resolución de la rama base y la cancelación.
- Linux only. El selector de carpetas usa
zenity/kdialog, y la cancelación lee/procpara encontrar los procesos hijo. Portarlo pidepsutily un diálogo por plataforma. - Una corrida a la vez. Arrancar una nueva deliberación cancela la anterior, por diseño.
- Sin histórico. El estado vive en el cliente mientras dura la corrida; al recargar se pierde.
- Servidor local sin autenticación, atado a
127.0.0.1. No lo expongas. EX_MODEyPRIORITYdel panel son decorativos, homenaje al original.
MAGI, NERV y Evangelion son propiedad de khara, inc. — esto es un homenaje de fan, sin ánimo de lucro.

{"agent": "melchior", "state": "running"} {"agent": "casper", "state": "rejected", "summary": "…", "findings": ["✕ …", "⚠ …"]} {"agent": "balthasar", "state": "aborted"} // solo tras un RESET {"status": "rejected"} // approved · rejected · idle