Automatización, JSON y solución de problemas
Sin preguntas interactivas#
Si falta un argumento obligatorio, es un error inmediato con una pista de uso, nunca una pregunta, y el comando sale con un código distinto de cero. Nada deja bloqueado a un script o a un agente esperando una respuesta.
Algunos comandos sí hacen preguntas, pero solo cuando hay una persona frente a una terminal:
zeltro createsolo pregunta en una terminal. Con--one-off,--json-outputo una entrada estándar que no es una terminal, vuelve al error inmediato.zeltro configurepregunta por el directorio de proyectos (y por tu nombre y correo de git si git no los tiene), salvo que pases--non-interactive(--yes,-y) o--json-output. Pasa--projects-dirpara definir el directorio sin que pregunte.zeltro ai-setsin opciones abre un menú en una terminal. Con cualquier opción, o sin terminal, no lo hace.zeltro uninstallpregunta si eliminar las imágenes de Docker, salvo que pases--delete-imageso--json-output.
Usa zeltro up-all / zeltro down-all para actuar sobre todos los proyectos en lugar de recorrerlos en un bucle.
Ejecutar comandos en un proyecto#
Usa zeltro exec <cmd> desde el directorio del proyecto. Se ejecuta sin TTY, con tu propio usuario para que los archivos montados sigan teniendo permisos de escritura, y devuelve el código de salida del comando. zeltro exec-root hace lo mismo como root. Los dos aceptan argumentos separados o una sola cadena entre comillas:
zeltro exec python3 manage.py migrate
zeltro exec "php artisan migrate --force"
zeltro bash, zeltro tinker y zeltro exec-tty / exec-tty-root son para uso interactivo y asignan una TTY cuando la hay. Tampoco uses un docker exec -u developer … a secas: el usuario developer del contenedor no es el dueño de los archivos de tu proyecto.
Ajustes de IA por sesión#
zeltro ai, resume, create, clone, create-installer y update-installer usan el agente definido con zeltro ai-set. Para usar otro en una sola ejecución, define estas variables en el entorno. Nunca se escriben en la configuración.
| Variable | Reemplaza |
|---|---|
ZELTRO_AI_AGENT |
El agente: codex, claude, agy, aider, qwen, opencode, hermes o gemini (obsoleto) |
ZELTRO_AI_MODEL |
El modelo |
ZELTRO_AI_API_BASE |
El endpoint de la API |
ZELTRO_AI_API_KEY |
La clave de API |
ZELTRO_AI_API_KEY_FILE |
La clave de API, leída de la primera línea del archivo. Tiene prioridad sobre ZELTRO_AI_API_KEY. |
ZELTRO_AI_LANGUAGE |
El idioma en el que responde el agente, por ejemplo Spanish. La salida propia de Zeltro sigue en inglés. |
Sin definir significa "usa el valor de ai-set"; definida pero vacía lo borra para esta ejecución. Un nombre de agente desconocido, un archivo de clave ilegible o un agente de reemplazo que no está instalado hacen que el comando salga con un código distinto de cero antes de que se ejecute nada. zeltro ai-set --install-only --agent <name> instala un agente sin convertirlo en el predeterminado.
Mensajes entre sesiones de agentes#
Cuando la app de Zeltro ejecuta sesiones de agentes en varios proyectos, pueden enviarse mensajes entre sí:
zeltro peers # live sessions, as project@host
zeltro send blog api -- "schema changed" # to one or more sessions
zeltro send --all -- "rebasing main" # to every other session
echo "long message" | zeltro send blog -- - # read the message from stdin
Ejecuta send desde dentro del directorio de tu proyecto; así sabe el destinatario quién lo envió. Todos los destinatarios tienen que estar activos o no se envía nada. Los mensajes tienen un límite de 16 KB. Los entrega la app, así que tiene que estar en ejecución.
Salida JSON#
--json-output produce una salida limpia y legible por máquinas para interfaces gráficas y scripts.
zeltro status --json-output
zeltro new laravel myapp --json-output
new imprime un objeto, con el resultado del paso de configuración anidado dentro:
{
"action": "new_project",
"project_name": "myapp",
"framework": "laravel",
"database": "mysql",
"setup_result": { "action": "setup_project", "status": "success", "...": "..." },
"status": "success"
}
Cuando la configuración tuvo que activar un servidor de base de datos, setup_result también incluye services_enabled (por ejemplo ["postgres"]) y admin_uis_suggested.
status imprime shared_services, indexado por nombre de contenedor, y projects:
{
"shared_services": {
"zeltro-mariadb": { "name": "zeltro-mariadb", "status": "running", "port": "3306", "resolved_ip": "10.x.x.2", "ping_status": "ok" }
},
"projects": [
{
"name": "my-api",
"project_ip": "10.x.x.219",
"external_port": "219",
"docker_running": true,
"http_status": "ok",
"local_url": "http://10.x.x.219",
"lan_url": "http://192.168.1.20:219",
"metadata": {}
}
]
}
El status de un servicio es running o stopped. Sin --all, projects solo lista los proyectos en ejecución.
Otras estructuras, todas con action y status:
| Comando | Salida |
|---|---|
enable-service (sin nombre) |
action: "list_services", always_on y services[] con slug, group, description, address, state (running, disabled o enabled_not_running) |
enable-service <name> / disable-service <name> |
action: "enable_service" / "disable_service", service, enabled (la nueva lista separada por espacios) |
ai-set (solo --json-output) |
action: "ai_set", agent, model, api_base, has_api_key, unattended, installed_agents. De solo lectura. |
peers |
action: "peers", this_host, me, app_running, updated_at, age_seconds, sessions[] |
send |
action: "send", id, from, to, file, app_running |
down |
action: "shutdown", target, project_name |
remove |
action: "remove_project", project_name, database_deleted |
Los errores imprimen "status": "error" con un campo message o error y salen con un código distinto de cero, así que comprueba el código de salida además del JSON.
Ejemplos de scripts:
# is the shared MariaDB up?
if zeltro status --json-output | jq -e '.shared_services["zeltro-mariadb"].status == "running"' >/dev/null; then
echo "Database is ready"
fi
# list stopped projects
zeltro status --all --json-output | jq -r '.projects[] | select(.docker_running == false) | .name'
Qué comandos la admiten#
Admitida: status, new, clone, setup, remove, up, down, down-all, start-services, stop-services, enable-service, disable-service, enable, disable, set-metadata, configure, create (incluido --classify-only), ai-set, peers, send.
En parte: install --json-output imprime el JSON de sus pasos setup y up, pero ningún objeto de resumen propio. uninstall --json-output solo se salta la pregunta sobre las imágenes; no imprime JSON.
No admitida: todo lo que se ejecuta dentro de un contenedor o se conecta directamente a un servicio: composer, art, wp, php, npm, npx, node, python, pip, shell, django, exec, supervisor, redis, memcache.
Si eres un agente de IA, nunca uses --json-output. Suprime toda la salida legible para personas, incluida la distinción entre éxito y fallo, así que no puedes saber si un comando funcionó de verdad. Existe para programas externos que analizan la salida de Zeltro, no para agentes que manejan la CLI.
Depuración#
zeltro new laravel test-project --debug
tail -f /tmp/zeltro-cli-debug.log
--debug funciona con new, clone, setup, up, down, status, remove, configure, start-services, stop-services y uninstall. Cada invocación sobrescribe el registro y anota el flujo de ejecución a través de los scripts a los que llama. Define DEBUG_LOG_PATH para escribirlo en otro lugar.
Solución de problemas#
| Síntoma | Qué revisar |
|---|---|
| Los servicios no arrancan | Que Docker esté en ejecución y que estés en el grupo docker (cierra sesión y vuelve a entrar después de instalar) |
| Errores de permisos | Lo mismo: ser miembro del grupo docker requiere iniciar sesión de nuevo |
| No puedes abrir un proyecto en el navegador | Usa la dirección que muestra zeltro status <project> (http://<project>/ no se resuelve en el host); luego docker logs <project-name> |
| Conexión a la base de datos rechazada | zeltro status: ¿está en ejecución el servicio compartido? Si aparece stopped, zeltro enable-service mysql (o postgres, mongo) |
| El proyecto da 502 después de reiniciar | Falta una dependencia en la imagen base. Consulta Arquitectura → Imágenes base |
| Fedora: permiso denegado en los archivos del proyecto | SELinux: vuelve a ejecutar zeltro configure para etiquetarlos de nuevo. Consulta Instalación |
| Arch: Docker no arranca después de instalar | La actualización del sistema reemplazó el kernel en uso: reinicia |
Comprobaciones útiles:
zeltro status # shared services and running projects
zeltro status --all # include stopped projects
zeltro status <project> # one project, even if stopped
docker logs <project-name>
zeltro exec "getent hosts zeltro-mariadb" # name resolution from inside the container
Herramientas gráficas#
Los instaladores incluyen ImageMagick (convert, magick) y rsvg-convert en el host, así que los proyectos que necesitan gráficos no tienen dependencias adicionales.
Prefiere generar SVG: los navegadores lo muestran a la perfección y es texto que un agente puede escribir directamente. Convierte solo cuando de verdad haga falta una imagen rasterizada:
rsvg-convert sprite.svg -o sprite.png # best SVG → PNG fidelity
convert -size 1200x800 gradient:'#1e3a8a-#04081d' bg.png # procedural backgrounds
Son herramientas del host: ejecútalas directamente, no mediante zeltro exec.
¿Encontraste un error en esta traducción? Avísanos en GitHub.