Ir al contenido

Rutinas

Una rutina es una tarea APX programada. El daemon corre un tick del scheduler cada 5 segundos y dispara cualquier rutina que esté vencida. Cada rutina tiene un kind, un schedule, un blob JSON spec opcional, y arrays de hooks de shell opcionales (pre_commands / post_commands).

Tipo¿LLM?¿Herramientas?Descripción
heartbeatNo—Registra un marcador. Útil como ping de “sigo vivo”.
shellNo—Corre un comando de shell. Captura el stdout.
exec_agentSíAllowlist del agenteCarga un agente del proyecto, corre spec.prompt con las tools de su campo tools: (no el registro del superagente) y persiste una conversación. allowed_tools: [] deja el path de texto de una sola llamada.
super_agentSíTodasCorre el agente APX por defecto con el registro completo de herramientas. Bucle multi-iteración.
telegramNo—Envía un spec.text fijo vía el plugin de Telegram.

Regla general para elegir:

  • ¿El agente del proyecto tiene que hacer el trabajo (archivos, Asana, tools)? → exec_agent.
  • ¿El agente APX por defecto, con el registro completo? → super_agent.
  • ¿Texto de un modelo, sin llamadas a tools? → exec_agent con allowed_tools: [].
  • ¿Shell puro sin LLM? → shell.
  • ¿Mensaje fijo de Telegram en un horario? → telegram.
FormatoEjemplosNotas
every:<N><unit>every:30s, every:5m, every:24h, every:7dEl más común.
once:<iso-8601>once:2026-12-01T08:00:00ZDispara una vez, después se deshabilita solo.
Expresión cron*/5 * * * *, 0 8 * * *Cron estándar de 5 campos.
Ventana de terminal
apx routine add <name> \
--kind <kind> \
--schedule <schedule> \
[--spec '<json>'] \
[--pre-commands 'cmd1,cmd2'] \
[--post-commands 'cmd'] \
[--skip-prompt-on signal|pre_failure|pre_success|always|never] \
[--permission-mode total|automatico|permiso] \
[--allowed-tools tool1,tool2] \
[--project <name|id|path>]

Configuración JSON específica del tipo:

TipoClaves de spec requeridasOpcionales
exec_agentpromptagent (slug, por defecto default)
super_agentprompt—
shellcmd—
telegramtext—
heartbeat(ninguna)—

Comandos de shell separados por comas. Forman un pipeline alrededor de la llamada al LLM:

  1. pre_commands corren secuencialmente. Su stdout combinado queda disponible como:

    • {{pre_output}} — sustituido en spec.prompt (y en spec.text) antes de la llamada al LLM. Siempre se sustituye: sin pre_commands, o sin salida, el hueco queda vacío en vez de llegarle al modelo como llaves literales.
    • $APX_PRE_OUTPUT — variable de entorno para post_commands.
    • $APX_PRE_OUTPUT_FILE — ruta a un archivo temporal con la salida completa (para payloads grandes).
  2. Corre el handler del tipo. Su resultado de texto se expone como $APX_LLM_OUTPUT.

  3. post_commands corren secuencialmente con $APX_LLM_OUTPUT, $APX_PRE_OUTPUT, y $APX_STATUS en el entorno.

Controla cuándo se saltea la llamada al LLM (fase 2), según lo que hicieron los pre_commands:

ValorComportamiento
signal (por defecto)Saltea el LLM cuando el stdout de los comandos pre contiene APX_SKIP. Los códigos de salida se ignoran. Es una señal de contenido, no una señal del sistema operativo — decide el comando pre.
pre_failureSaltea el LLM cuando el último comando pre sale distinto de cero.
pre_successSaltea el LLM cuando el último comando pre sale cero. Es el opuesto exacto de pre_failure — sirve cuando que el comando pre salga bien significa que no queda nada para pensar.
alwaysSiempre saltea el LLM — útil para pipelines pre→post puros.
neverSiempre corre el LLM, hagan lo que hagan los comandos pre.

Los post_commands corren siempre, se haya salteado el LLM o no; $APX_SKIPPED vale 1 cuando se salteó.

Emitir la señal de skip desde un comando pre se ve así:

Ventana de terminal
apx routine add digest \
--pre 'test -s ~/report.txt || echo APX_SKIP' \
--skip-prompt-on signal

Sobreescribe el super_agent.permission_mode global para esta rutina: total | automatico | permiso.

Una rutina corre con el modelo propio de su agente (exec_agent) o el del super-agente, y cae al router. Para darle a un trabajo otro modelo, usá --model proveedor:modelo (spec.model, panel: Modelo de la rutina). Si ese modelo falla, la corrida sigue con el modelo del agente y después con el router — el modelo de la rutina es una elección para ese trabajo, nunca reemplaza al del agente.

Ventana de terminal
apx routine list [--project <name|id|path>]
apx routine get <name> [--project <name|id|path>]
apx routine history <name> [--project <name|id|path>]
apx routine run <name> [--project <name|id|path>] # forzar disparo ahora
apx routine enable <name> [--project <name|id|path>]
apx routine disable <name> [--project <name|id|path>]
apx routine remove <name> [--project <name|id|path>]
apx
$ apx routine list --project myapp
project #2 routines:
NAME                EN KIND        SCHEDULE         NEXT_RUN              LAST
morning-standup     ✓  exec_agent  every:1h          2026-06-14 10:00:00   ✓ 2026-06-14 09:00:02
daily-weather       ✓  telegram    once:08:00        2026-06-15 08:00:00   ✓ 2026-06-14 08:00:01
healthcheck         ✓  heartbeat   every:5m          2026-06-14 09:35:00   ✓ 2026-06-14 09:30:00
nightly-backup      ✗  shell       once:02:00        —                     ✗ 2026-06-13 02:00:04
apx routine list — nombre, tipo, programación, habilitada, próxima ejecución, última ejecución
Ventana de terminal
apx routine add daily-weather \
--project myapp \
--kind exec_agent \
--schedule "every:24h" \
--spec '{"agent":"default","prompt":"El clima es {{pre_output}}. Una frase amigable, sin saludos."}' \
--pre-commands "curl -s 'https://wttr.in/London?format=%t+%C+viento+%w'" \
--post-commands 'apx telegram send "$APX_LLM_OUTPUT"'

Super-agente con herramientas, horario de mañana

Sección titulada «Super-agente con herramientas, horario de mañana»
Ventana de terminal
apx routine add morning-standup \
--project myapp \
--kind super_agent \
--schedule "0 9 * * *" \
--spec '{"prompt":"List open tasks across projects and send me a short summary via Telegram."}' \
--permission-mode automatico
Ventana de terminal
apx routine add db-backup \
--project myapp \
--kind shell \
--schedule "every:24h" \
--spec '{"cmd":"pg_dump mydb > /backups/mydb-$(date +%F).sql"}'
Ventana de terminal
apx routine add deploy-prod \
--project myapp \
--kind super_agent \
--schedule "once:2026-07-01T10:00:00Z" \
--spec '{"prompt":"Run the production deploy checklist and report status."}'
Ventana de terminal
# ✗ Frágil — depende de la heurística de supresión
--kind super_agent \
--spec '{"prompt":"El clima es {{pre_output}}. Mandalo por Telegram."}' \
--post-commands 'apx telegram send "$APX_LLM_OUTPUT"'
# ✓ Limpio — el modelo escribe el texto, la shell lo entrega
--kind exec_agent \
--spec '{"prompt":"El clima es {{pre_output}}. Una frase amigable, sin saludos."}' \
--post-commands 'apx telegram send "$APX_LLM_OUTPUT"'
Ventana de terminal
apx routine history <name> --project myapp # últimas N ejecuciones con estado y salida
apx log -f # seguir el log unificado del daemon
apx messages tail --channel routine -n 20 # últimos 20 mensajes del canal routine

Una rutina que “no envía nada” lo más frecuente es que signifique: enabled: false, next_run_at está en el futuro, o el LLM devolvió texto vacío. Revisá apx routine history primero — el campo result.text muestra exactamente lo que produjo el modelo.

La pantalla Rutinas del panel muestra la corrida que está pasando ahora, no sólo las que terminaron. Una rutina corriendo queda marcada desde el momento en que arranca, la lista de ejecuciones dibuja sus pasos a medida que el agente los da, y cada ejecución terminada linkea al chat donde quedó archivada. Ese estado vive en el daemon: sobrevive un refresh, se ve igual en todos los paneles abiertos, y muestra también las corridas que disparó el scheduler sin que nadie estuviera mirando. Un reinicio del daemon lo borra — la corrida se murió con el proceso.

  • Tareas — lista de TODO por proyecto que las rutinas pueden leer y escribir.
  • Super-agente — el modo bajo el cual corren las rutinas super_agent.
  • Configuración — fallback de modelo global y configuración de permisos.