Escribir scripts
Crear un script Python, entender el contrato main(input), ejecutarlo a mano y leer el historial de ejecuciones.
Un script es lógica en Python que corre en el servidor, dentro de la app. Es la pieza correcta para todo lo que no es una pantalla ni una query simple: sincronizar datos con otro sistema, recalcular indicadores todas las mañanas, generar un Excel y enviarlo por correo, validar un archivo subido por una API.
El mismo script puede dispararse de tres maneras — y el código no cambia:
| Disparo | Cómo ocurre |
|---|---|
| Manual | Botón Ejecutar ahora en el editor, con argumentos opcionales. |
| Cron | Una programación (capítulo Programaciones) — a horas concretas, en intervalos, o en una ventana de vigilancia. |
| API | Como paso de una API de la app — el script recibe los argumentos de la petición y el resultado del paso anterior. |
A lo largo de esta página usamos el script atualizar_indicadores de la
app Gestión de Clientes, que recalcula los indicadores comerciales del
CRM todas las mañanas.
Dónde viven los scripts
Dentro de la app, los scripts tienen su sección en el árbol lateral — el grupo Scripts. Cada script es un nodo del árbol: hacer clic en el nombre abre el editor en una pestaña del espacio de trabajo, y la flecha de la izquierda expande el nodo para mostrar sus Archivos, Dependencias y Programaciones (páginas siguientes de este capítulo).
Hay también una vista de lista — la página Scripts — con una fila por script:
| Columna | Qué muestra |
|---|---|
| Nombre | Nombre y descripción del script. |
| Runtime | El lenguaje de ejecución (Python). |
| Estado | Activo o Borrador — solo los activos corren por programación. |
| Programaciones | Cuántas programaciones existen, cuántas están activas, y Próxima: con la fecha de la próxima ejecución prevista. |
| Última ejecución | El estado (Éxito, Error, …) y la hora de la ejecución más reciente. |

Crear un script
En el árbol lateral, pasa el ratón por la fila del grupo Scripts y haz clic en el botón + (Nuevo script).
Rellena el modal Nuevo script:
Campo Notas Nombre Obligatorio. Ej.: sincronizar-clientes. Por este nombre el script se referencia en las programaciones y en las APIs.Runtime Fijo: Python. La ejecución en el servidor es solo Python. Descripción Opcional — «¿Qué hace este script?» aparece en la lista y en el árbol. Tiempo límite 30 segundos, 1 minuto, 2 minutos, 5 minutos o 10 minutos. Al excederlo, el proceso se termina y la ejecución queda marcada como timeout. Haz clic en Crear script. El script nace con el código inicial (el contrato a la vista, en comentarios) y el editor se abre de inmediato en una pestaña.

Nota
El runtime queda definido en la creación y no se cambia después. El nombre, la descripción, la versión y el tiempo límite pueden cambiarse en cualquier momento en las Definiciones del script.
El contrato: main(input)
Todo script tiene un archivo de entrada, main.py, con una función main.
La plataforma la llama en cada ejecución y el valor devuelto es el
resultado del script:
def main(input):
return {"ok": True}
El parámetro input trae siempre tres claves:
| Clave | Contenido |
|---|---|
input["args"] |
Diccionario con los argumentos de la ejecución — los que escribiste en el modal Ejecutar ahora, los definidos en la programación, o los que la API pasó. Los valores llegan como texto. |
input["prev"] |
El resultado del paso anterior, cuando el script corre dentro de una API. En las ejecuciones manuales y programadas es None. |
input["context"] |
Metadatos de la ejecución: nombre e identificador del script, el disparo ("manual", "cron", "api" o "catchup"), el número de la ejecución, y quién llamó. |
Reglas del resultado:
- Tiene que ser serializable en JSON: diccionarios, listas, textos,
números, booleanos o
None. Los objetos de otros tipos hacen fallar la ejecución. - El tamaño máximo del resultado es 32 MB.
- Una excepción no capturada hace que la ejecución termine en Error, con el traceback completo en los logs.
Todo lo que imprimas — con print o con el log(...) del SDK — aparece en
los logs de la ejecución, línea a línea. Para acceder a datos, llamadas
HTTP, secretos, notificaciones y más, usa el SDK api_manager, descrito en
la página El SDK de los scripts.
El editor
El editor ocupa la pestaña del script a todo el ancho. En la barra sobre el
código ves la ruta del archivo activo (main.py al principio) con un punto
de estado al lado — Guardado o Cambios por guardar. No hay botón de
guardar código: los cambios se guardan solos alrededor de un segundo
después de que dejes de escribir.

A la derecha de la barra están los botones:
| Botón | Qué hace |
|---|---|
| Ejecutar ahora (▶) | Guarda todo y abre el diálogo de ejecución manual. |
| Ejecuciones | Abre el historial de ejecuciones del script. |
| Prompt para LLM | Abre un texto listo para copiar con todo el contrato del SDK, para pedir el script a un asistente de IA — ver El SDK de los scripts. |
| Maximizar editor | El editor pasa a ocupar toda la pantalla; Esc o Minimizar editor vuelven a lo normal. |
Mientras escribes Python, el editor autocompleta: sugiere los módulos y
funciones del SDK (db, http, log, …), tus propios archivos y los
packages pip instalados en el entorno del script, muestra la firma de los
parámetros mientras rellenas una llamada, y documentación al pasar el
cursor sobre un nombre.
Consejo
El icono Abrir en pestaña propia junto a la ruta abre el archivo activo en una pestaña solo suya — útil para ver dos archivos del script lado a lado. El archivo sale del editor principal: un archivo tiene siempre un único editor.
Los archivos Python se guardan formateados por ruff, que la plataforma
instala en un entorno propio la primera vez que hace falta (necesita acceso a
pypi.org). El editor no toca lo que estás escribiendo mientras escribes: el
código formateado aparece al volver a abrir el archivo, o al momento con
Formatear código (Shift+Alt+F).
Ejecutar a mano
- Haz clic en Ejecutar ahora (▶). Lo que esté por guardar se guarda primero.
- En el diálogo, define los argumentos de esta ejecución (opcional): haz
clic en Añadir argumento y rellena Nombre (ej.:
clienteId) y Valor. Los valores llegan al script como texto, eninput["args"]. - Haz clic en Ejecutar.

El panel Resultado de la ejecución, bajo el editor, muestra de inmediato:
- el estado — Éxito o Error — y la duración en milisegundos;
- el valor devuelto por
main, formateado como JSON; - los Logs, con cada línea escrita por
log(...)oprint.
Si la ejecución falla, el mensaje de error aparece en el lugar del resultado, y el traceback completo queda en los logs.
El panel tiene dos zonas, Resultado y Logs, con un divisor arrastrable entre ellas; cada zona se pliega con un clic en el título, y la división se recuerda. La altura del panel también se arrastra, por el borde superior.
Para ver el código y el resultado lado a lado, pulsa Abrir la consola en otra pestaña: la consola se abre en una pestaña propia a la derecha del editor, que puedes arrastrar donde quieras. Mientras exista esa pestaña, el panel inferior del editor deja paso a una línea con el botón Mostrar, que la enfoca; ejecutar sigue haciéndose en el editor y el resultado aparece en la consola. Cerrar la pestaña devuelve el panel al editor, con el último resultado.
El historial de ejecuciones
Haz clic en Ejecuciones en la barra del editor. El modal lista todas las ejecuciones del script, con filtros por estado, origen, duración y fecha:
| Columna | Contenido |
|---|---|
| Inicio | Fecha y hora en que la ejecución empezó. |
| Origen | Manual, Cron, API o Recuperación (ejecución recuperada de una programación que quedó sin correr). |
| Estado | Ver tabla abajo. |
| Duración | En milisegundos. |
Los estados posibles:
| Estado | Significa |
|---|---|
| Éxito | main devolvió un resultado sin error. |
| Error | Una excepción no capturada, o un resultado no serializable. |
| Corriendo | La ejecución aún no terminó. |
| Timeout | Excedió el Tiempo límite del script y fue terminada. |
| Abortado | El proceso fue terminado antes del final (ej.: parada del servidor). |
| Saltado (solapamiento) | Una programación se disparó mientras la ejecución anterior aún corría — esta no llegó a correr. |
Haz clic en Detalles en una fila para expandirla: ves los Argumentos con los que corrió, el Resultado devuelto, el Error (si lo hubo) y los Logs completos.

Nota
El historial guarda lo esencial, no todo: los resultados y logs muy largos se truncan en el registro. El panel Resultado de la ejecución justo después de una ejecución manual es el sitio correcto para inspeccionar salidas grandes.
Activo o borrador
En la cabecera del panel del script hay un interruptor Activo. Un script con el interruptor apagado queda en Borrador:
- no corre por programación — las horas previstas quedan registradas como Saltada, con la nota «El script está en borrador»;
- sigue pudiendo ejecutarse a mano en el editor, para probarlo con calma.
Es la forma de desarrollar con tranquilidad: escribe, prueba con Ejecutar ahora, y solo enciende el Activo cuando el script esté listo para correr solo.
Definiciones del script
Abre las Definiciones del script (en el menú de acciones del script en el árbol, o por la cabecera del panel) para cambiar:
| Campo | Notas |
|---|---|
| Nombre | El nombre por el que las programaciones y las APIs lo referencian. |
| Versión | Mostrada donde este script se usa como dependencia de otro (app/script@versión). |
| Descripción | Texto libre. |
| Tiempo límite | Las mismas opciones de la creación, de 30 segundos a 10 minutos. |
El runtime no aparece para edición — queda definido en la creación.
Preguntas frecuentes
¿Por qué la ejecución aparece como Timeout? El script tardó más que el Tiempo límite definido. Sube el límite en las Definiciones del script (máximo: 10 minutos) o divide el trabajo — por ejemplo, procesa en lotes más pequeños por ejecución.
Escribí en el editor y ejecuté enseguida — ¿corrió la versión antigua? No. Ejecutar ahora guarda primero todo lo que esté por guardar; la ejecución usa siempre lo que está en pantalla.
¿El resultado se devuelve bien pero los argumentos llegan «mal»?
Los argumentos llegan siempre como texto. Un argumento limite = 10
llega como "10" — conviértelo en el código:
int(input["args"].get("limite", 0)).
¿Puedo guardar estado entre ejecuciones? Cada ejecución es un proceso aislado — las variables no sobreviven de una a otra. Para persistir algo, escribe un archivo en la carpeta del script (ver Dependencias y archivos) o guarda los datos en un datasource.