Guías

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

  1. Instalá OpenCode, corré opencode una vez y conectá un proveedor. Los modelos gratuitos de Zen no necesitan clave. opencode models lista lo que podés usar.

  2. 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
  3. 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í.

  4. Corré vx doctor. Cuando un perfil selecciona opencode, o hay un binario opencode en tu PATH, 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 el PATH, 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-scout

En un perfil de OpenCode los dos campos significan:

CampoValorQué pasa
modelprovider/model, con un #variant opcional, como opencode/glm-5.3-flash-free o anthropic/claude-sonnet-5#highel soldier arranca con ese modelo, y con ese variant cuando hay uno
effortcualquier etiqueta simple, como low o mediumse 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:

  1. 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 sin OPENCODE_CONFIG, OPENCODE_CONFIG_DIR ni OPENCODE_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 api levantarí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á.
  2. 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 en failed, y vx strike la quita.
  3. 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.
  4. El arranque. El soldier arranca como opencode --auto --session <id>, con OPENCODE_DISABLE_AUTOUPDATE=1 en 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

TemaSoldier de Claude CodeSoldier 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 promptse tipea en el panese 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.
ReglasCLAUDE.md, que importa AGENTS.mdOpenCode 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.
Pluginsn/aLos 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.
Skillslas .claude/skills del proyectoninguna. En esta versión los soldiers no usan skills.
Preguntasel selector de preguntas de Claudeel formulario de preguntas y el prompt de permiso propios de OpenCode. Ver abajo.
vx shipel reviewer y el fixer del tribunal corren claude -pcorren 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ó:

Pantallavx decide <task-id> <answer>
Prompt de permisoallow 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 preguntael 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.xse 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 effort en 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

En esta página