Usar OpenCode
Corré los soldiers de un perfil de modelo en OpenCode en lugar de Claude Code, en OpenCode 1.x o 2.x, incluidos sus modelos gratuitos de Zen.
Un perfil de modelo puede nombrar un harness, el CLI de agente en el que corren sus soldiers. Con "harness": "opencode" los soldiers de ese perfil corren en OpenCode, que puede usar muchos proveedores y modelos, incluidos los gratuitos. El commander sigue en Claude Code salvo que elijas otra cosa (mirá OpenCode como commander), y una tarea conserva su harness a través de vx redispatch, vx prompt, vx decide, vx land y vx strike.
OpenCode tiene dos generaciones que comparten el comando opencode, y vexillum maneja las dos:
- 2.x (verificada contra 2.0.32). Su TUI no tiene el flag
--model, así que vexillum crea la sesión del soldier con ese modelo a través del servicio en segundo plano de OpenCode y la abre. - 1.x, desde 1.18.29. Su TUI acepta
--model.
vx dispatch corre opencode --version y registra la serie mayor en la tarea, y vx redispatch, vx prompt y vx decide usan la misma. Una tarea despachada en 2.x no se relanza en 1.x: instalá la serie con la que se despachó, o hacé strike y despachá de nuevo. Nada de la versión se guarda en caché entre comandos.
Solo algunos modelos gratuitos no retienen tu código
Un soldier le manda al proveedor del modelo todo lo que lee: tus prompts, los archivos que abre, la salida de los comandos y lo que haya en tu entorno que un comando imprima. La documentación del propio OpenCode (opencode.ai/docs/zen, leída el 2026-10-19) nombra cuatro modelos gratuitos de Zen como de retención cero: glm-5.3-flash-free, deepseek-v4.1-flash-free, minimax-m3.1-flash-free y longcat-2.5-preview-free. Varios otros figuran como que recolectan datos para mejorar el modelo o como que los retienen 30 días, y un modelo gratuito que la página no menciona, como space-bunny-free, no está documentado como de retención cero, así que tratalo como si registrara todo. Un modelo gratuito tampoco da garantías como commander. Los términos cambian, así que leelos antes de apuntar un perfil a un modelo gratuito, y no uses uno con código privado o propietario, ni en una máquina cuyos archivos o entorno guarden secretos. OpenCode, igual que Claude Code en vexillum, tiene acceso total al host con tu usuario.
Solo OpenCode 2.x se verificó en vivo
El lanzamiento en 2.x, el manejo de pantallas bloqueadas y el one-shot que usa vx ship se probaron en un OpenCode 2.0.32 real. Los caminos de 1.x salen de las fuentes de 1.18.29 y 1.19.3 y están cubiertos por tests contra un opencode falso que informa 1.x, no por un 1.x real. docs/verification/opencode-soldier-checklist.md en el repositorio lista cada paso que falta confirmar.
Prepararlo
-
Instalá OpenCode, corré
opencodeuna vez y conectá un proveedor. Los modelos gratuitos de Zen no necesitan clave.opencode modelslista lo que podés usar. -
Instalá la integración de herdr para OpenCode, así herdr lee el estado de un soldier (working, idle, blocked) del propio OpenCode en lugar de leer la pantalla:
herdr integration install opencode -
Corré el TUI de OpenCode una vez después de cada actualización de OpenCode, antes de despachar. Una versión nueva puede mostrar un diálogo de "what's new" en su primer arranque. Nadie está en el pane de un soldier para cerrarlo, así que el soldier se quedaría ahí.
-
Corré
vx doctor. Cuando un perfil seleccionaopencode, o hay un binarioopencodeen tuPATH, informa el binario, su versión (1.x desde 1.18.29, o 2.x), si una instalación 1.x más vieja tapa a una 2.x anterior en elPATH, y la integración de herdr. Solo advierten: una pieza faltante nunca deja el entorno como no listo, y una configuración sin OpenCode no ve ninguna de estas líneas.
Agregar un perfil
Agregá un perfil con "harness": "opencode" a .vexillum/models.json (o al global ~/.vexillum/models.json). El mismo perfil sirve en 1.x y en 2.x:
{
"profiles": {
"opencode-scout": {
"model": "opencode/glm-5.3-flash-free",
"effort": "low",
"when": "Scout whose question reduces to verifiable facts, run on a free zero-retention model.",
"harness": "opencode"
},
"opencode-mission": {
"model": "anthropic/claude-sonnet-5#high",
"effort": "medium",
"when": "Mission on OpenCode with Sonnet at its high variant.",
"harness": "opencode"
}
}
}vx dispatch "which flags does the build script accept?" --kind scout --profile opencode-scoutEn un perfil de OpenCode los dos campos significan:
| Campo | Valor | Qué pasa |
|---|---|---|
model | provider/model, con un #variant opcional, como opencode/glm-5.3-flash-free o anthropic/claude-sonnet-5#high | el soldier arranca con ese modelo, y con ese variant cuando hay uno |
effort | cualquier etiqueta simple, como low o medium | se registra en la tarea y se muestra en vx status, nunca se le pasa a OpenCode |
vexillum revisa la forma cuando lee el perfil. En 2.x, vx dispatch además comprueba el provider, el modelo y el variant contra lo que OpenCode lista para el camp (mirá Qué modelo recibe un soldier); en 1.x, OpenCode informa un modelo que no tiene cuando el soldier arranca. El effort no se convierte en un variant porque los nombres de variant cambian según el modelo: el high de un modelo es el error de otro. Un variant se usa solo cuando el perfil lo escribe después del #.
Un variant que el modelo no tiene es un error. En 2.x vx dispatch lo rechaza y nombra los variants que el modelo sí tiene. Un one-shot (el reviewer y el fixer de vx ship, que usan opencode run) falla con Variant unavailable for <model>: <variant>. El pie del pane del soldier muestra el variant, como · high, cuando se aplica; revisalo la primera vez que uses un variant.
Qué modelo recibe un soldier
En 2.x al TUI no se le puede decir un modelo por la línea de comandos, y la configuración que decide el modelo la lee el servicio compartido en segundo plano de OpenCode, no el TUI. Un archivo escrito en el camp, o una variable de entorno en el pane, o chocaría con la configuración de OpenCode propia de un proyecto o se ignoraría. Por eso vx dispatch le da a cada soldier una sesión propia:
- El servicio. vexillum se asegura de que el servicio en segundo plano de OpenCode esté corriendo. Si no lo está, lo levanta él mismo con
opencode service start, desde un entorno sinOPENCODE_CONFIG,OPENCODE_CONFIG_DIRniOPENCODE_CONFIG_CONTENT. El servicio lee esas variables una sola vez, al arrancar, y las conserva para toda ventana de OpenCode que se conecte después.opencode apilevantaría un servicio detenido con el entorno que tenga quien lo llama, y lo mismo haría el TUI del propio soldier, así que vexillum levanta el servicio primero y no se lo deja a ellos. Un servicio que ya está corriendo se usa tal cual está. - La comprobación. vexillum le pregunta al servicio qué modelos puede correr para el camp y comprueba el provider, el modelo y el variant del perfil contra esa lista. Cuando alguno no está, el dispatch falla antes de que exista ningún pane y nombra lo que sí existe, por ejemplo
OpenCode's provider "anthropic" has no model "claude-sonnet-9"; its models: .... La tarea queda enfailed, yvx strikela quita. - La sesión. vexillum crea una sesión ubicada en el camp, con el modelo y el variant del perfil, titulada
vexillum <task-id>. No fija agente ni reglas de permisos. - El arranque. El soldier arranca como
opencode --auto --session <id>, conOPENCODE_DISABLE_AUTOUPDATE=1en su pane.
El modelo de una sesión está por encima del model propio del proyecto y del modelo propio de su agente por defecto, así que un proyecto que fija su propio agente o modelo por defecto no pisa al perfil. Solo el agente propio del soldier corre con el modelo de la sesión: los subagentes integrados de OpenCode conservan los modelos con que están configurados, y el soldier todavía puede cambiar de modelo en su TUI.
No se escribe nada en el camp ni en el proyecto, ninguna variable de entorno lleva configuración y no se agrega ninguna línea a info/exclude. El opencode.json u opencode.jsonc propio de un proyecto, sus agentes (incluso uno llamado vx-soldier), su agente por defecto y sus deny de permisos valen exactamente igual que cuando corrés OpenCode ahí. Un repositorio que versiona configuración de OpenCode se despacha como cualquier otro, y una mission puede crear opencode.json o .opencode/ sin git add -f. Una tarea sin modelo arranca un OpenCode común con los valores por defecto del proyecto, sin sesión.
El id de la sesión queda registrado en la tarea (harness_session en vx status --json). vx redispatch vuelve a abrir la misma sesión cuando el servicio todavía la tiene y está ubicada en el camp que la tarea recupera, así que la conversación continúa. Si el servicio la perdió (se borró, o se reinició su data) o el camp es otro, vexillum crea una sesión nueva. vx strike no borra la sesión: queda en la lista de sesiones de OpenCode, titulada vexillum <task-id>, hasta que la borres ahí.
En 1.x no se crea ni se escribe nada: el modelo va con --model, y un variant con la variable de entorno OPENCODE_CONFIG_CONTENT del pane del soldier. Las dos generaciones fijan OPENCODE_DISABLE_AUTOUPDATE=1, para que un soldier en marcha no se actualice por debajo.
Las versiones anteriores de vexillum escribían .opencode/agents/vx-soldier.md y opencode.json en el camp de un soldier de 2.x y agregaban /.opencode/ y /opencode.json al info/exclude del repositorio. A un camp reutilizado que todavía tenga esos archivos se le quitan antes del siguiente arranque, pero solo si son idénticos byte a byte a lo que escribió vexillum, así que una edición tuya nunca se borra. Las líneas de info/exclude se dejan como están, porque un soldier arrancado por una versión anterior puede seguir dependiendo de ellas. Ahora no hacen nada, salvo ocultar de git status un opencode.json sin versionar en tu checkout principal; borralas de .git/info/exclude cuando no quede ningún soldier de una versión anterior corriendo.
Permisos
Un soldier arranca con --auto, que aprueba todo permiso que no esté negado explícitamente. vexillum no fija reglas de permisos propias, ni en la sesión ni en ningún otro lugar. En 2.x gana la última regla que coincide, así que una regla comodín de vexillum pisaría los deny de tu propia configuración de OpenCode. Sin una regla propia, tus deny siguen valiendo dentro de un soldier. Como con todo harness, aterrizar es el control: nada llega a tu historial hasta que aprobás vx land.
Qué cambia respecto de un soldier de Claude Code
| Tema | Soldier de Claude Code | Soldier de OpenCode |
|---|---|---|
| Permisos | --dangerously-skip-permissions | --auto; tus reglas deny siguen valiendo. Ver arriba. |
| Modelo | --model y --effort | --model en 1.x; una sesión creada para el soldier en 2.x. El effort se registra, no se pasa. |
| Primer prompt | se tipea en el pane | se entrega con herdr agent prompt cuando el pane está listo. vx dispatch espera a que se despeje un error de arranque agent_not_ready antes de tratar el arranque como fallido. |
| Reglas | CLAUDE.md, que importa AGENTS.md | OpenCode lee AGENTS.md y, solo cuando no hay, CLAUDE.md. No expande @AGENTS.md ni ninguna otra referencia @archivo dentro de ellos. El bloque de vexillum vive en AGENTS.md (o en CLAUDE.md cuando el proyecto no tiene AGENTS.md), y OpenCode lee el que lo tenga. |
| Plugins | n/a | Los plugins de V1 no corren en V2. Un proyecto que dependa de uno para su flujo se comporta distinto con un soldier de 2.x. |
| Skills | las .claude/skills del proyecto | ninguna. En esta versión los soldiers no usan skills. |
| Preguntas | el selector de preguntas de Claude | el formulario de preguntas y el prompt de permiso propios de OpenCode. Ver abajo. |
vx ship | el reviewer y el fixer del tribunal corren claude -p | corren opencode run --auto --format json con el modelo y el variant de la mission, sin entrada por stdin |
Soldiers bloqueados
Con --auto un prompt de permiso es raro, y la forma habitual en que un soldier de OpenCode se bloquea es su formulario de preguntas. vx decide responde lo que reconoce, solo en 2.x, y vuelve a leer el pane justo antes de teclear para no escribir nunca en una pantalla que ya cambió:
| Pantalla | vx decide <task-id> <answer> |
|---|---|
| Prompt de permiso | allow once pulsa Enter. reject pulsa Esc, y el soldier ve "The user declined this tool call". always allow se rechaza: puede guardar una regla para siempre, y una respuesta de una línea no puede cargar esa decisión. |
| Formulario de pregunta | el número de una opción (2) o su texto exacto la elige con pulsaciones de flecha abajo y Enter. Cualquier otro texto se teclea en el campo "Type your own answer" del formulario, una pulsación por carácter, así que se limita a ASCII imprimible. Un número suelto que no es una opción se rechaza en lugar de teclearlo. |
| Una pantalla que vexillum no conoce, o cualquiera de 1.x | se rechaza, sin teclear nada. Conectate al pane con herdr y respondé ahí. |
Sin pantalla bloqueada (el soldier terminó su turno con una línea needs-decision:) | la respuesta se entrega como texto plano, como con cualquier otro harness |
herdr mismo rechaza herdr agent prompt con agent_blocked mientras un pane está bloqueado, y por eso una respuesta tecleada entra con pulsaciones de teclas. Ver Blocked e interrupted.
Fuera de esta versión
- Convertir
efforten un variant. - Respuestas estructuradas para un formulario de varias preguntas.
- Skills para los soldiers de OpenCode.
Para una checklist que verifique una configuración de OpenCode, 1.x en particular, en una máquina real, mirá docs/verification/opencode-soldier-checklist.md en el repositorio.
Relacionado
Pi como commander
Corré el commander, el agente con el que hablás, en Pi en lugar de Claude Code, o en los dos, y cómo vexillum lo despierta cuando un soldier termina.
OpenCode como commander
Hablale al commander en OpenCode 2.x en lugar de Claude Code, y cómo el sentinel lo despierta a través de la API HTTP de OpenCode.