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 create solo pregunta en una terminal. Con --one-off, --json-output o una entrada estándar que no es una terminal, vuelve al error inmediato.
  • zeltro configure pregunta 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-dir para definir el directorio sin que pregunte.
  • zeltro ai-set sin opciones abre un menú en una terminal. Con cualquier opción, o sin terminal, no lo hace.
  • zeltro uninstall pregunta si eliminar las imágenes de Docker, salvo que pases --delete-images o --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.