Se ejecuta enWrit CloudDesktopAutoalojado
En esta página
Workflows.
Un workflow es una lista ordenada de pasos que se ejecuta en un navegador real y devuelve datos estructurados. Créalo una vez — grabándolo o describiéndolo — y luego ejecútalo bajo demanda, según una programación, desde un webhook, o como endpoint publicado y MCP tool.
Writ se ejecuta en tus propias cuentas, con tus propias credenciales y datos, en los sitios que estás autorizado a usar.
objeto ▸ la forma
El objeto workflow.
Un workflow es JSON simple: un nombre, un array steps ordenado y las entradas declaradas por defecto contra las que se resuelven sus placeholders. Cada paso es un objeto pequeño con un type y una config.
{
"name": "Product extractor",
"description": "Prices from the catalog",
"workflow_type": "recorded",
"steps": [
{ "type": "navigate", "config": { "url": "{{url}}" } },
{ "type": "extract", "config": { "fields": {
"title": ".product .title",
"price": ".product .price"
} } }
],
"form_data": { "url": "https://example.com/catalog" },
"timeout_ms": 120000,
"headless": true
} pasos ▸ el vocabulario
30+ tipos de paso.
Los pasos se ejecutan en orden, y cada uno puede leer lo que produjeron los anteriores. El vocabulario abarca navegación, interacción, esperas, extracción, pestañas, IA, autenticación y control de flujo — cada tipo está en la referencia de pasos con sus campos, un ejemplo real y su comportamiento.
Navegación
Interacción
Esperas
Extracción
Pestañas
IA
Autenticación
Flujo
io ▸ entradas y salidas
Entradas dentro, datos estructurados fuera.
Una ejecución lleva sus entradas en el campo de cuerpo form_data. Dentro de los valores de los pasos, los placeholders se resuelven al ejecutar — la receta se mantiene genérica y nada sensible se guarda en ella:
| Placeholder | Se resuelve en |
|---|---|
{{key}} | La clave correspondiente del form_data de la ejecución, en su defecto los valores por defecto guardados del workflow. |
{{vault:name}} | Un secreto de tu vault, inyectado al ejecutar. Los secretos son interpolación dentro del valor de un paso — nunca un paso propio. |
{{extracted:key}} | Un valor extraído por un paso anterior de la misma ejecución — para encadenar peticiones api_call. |
{{file:slot}} | Un archivo almacenado vinculado al hueco con nombre (subidas, descargas capturadas). |
A la salida, los pasos extract rellenan extracted_data y la ejecución se resuelve con result_data — la carga estructurada que lee tu llamador.
ejecutar ▸ la api
Ejecutar un workflow.
Un solo endpoint inicia una ejecución. Por defecto la llamada espera el veredicto; desactiva wait para recibir de inmediato un identificador de tarea.
POST /api/v1/workflows/{workflow_id}/runs?wait=true&timeout=120
Authorization: Bearer wt_xxxxxxxxxxxx
{ "form_data": { "url": "https://example.com/catalog" } }
# wait=true (default) — the call blocks until the run settles:
{
"status": "success",
"success": true,
"result_data": { "title": "…", "price": "…" },
"extracted_data": { "title": "…", "price": "…" },
"error": null,
"duration_ms": 8412
}
# wait=false — returns immediately with a task handle:
{ "task_id": "…", "status": "pending", "workflow": { "…": "…" } } | Parámetro de consulta | Rol |
|---|---|
wait | true por defecto — la llamada HTTP bloquea hasta que la ejecución se resuelve. |
timeout | Cuánto esperar, en segundos. 120 por defecto, rango aceptado 10–300. |
Con wait=false la respuesta es {"task_id", "status": "pending", "workflow"} — consulta la ejecución, o suscríbete a sus eventos.
Desde los SDKs
En tu propia máquina, los SDKs publicados descubren el agente local y ejecutan el mismo workflow sin cargo de cómputo:
run.ts
import { WritAgent, runRowId } from "@usewrit/agent-sdk";
const client = new WritAgent(); // discovers the running agent + token
const { data: workflows } = await client.workflows.list();
const run = await client.workflows.runAndWait(workflows[0].id, {
inputs: { city: "Paris" },
});
const { data: rows } = await client.runs.data(runRowId(run));
console.log(run.status, rows); run.py
from writ_agent import WritAgent, run_row_id
with WritAgent() as client: # discovers the local daemon
run = client.workflows.run_and_wait(3, inputs={"city": "Paris"})
print(run["status"], run["rows_extracted"])
print(client.runs.data(run_row_id(run))["data"]) # extracted rows run.go
client, err := writ.Discover(ctx) // find the running agent
page, _ := client.Workflows.List(ctx, nil)
item, _ := client.Workflows.RunAndWait(ctx, page.Data[0].ID, nil)
rowID, _ := item.RowID()
csv, _ := client.Runs.DataCSV(ctx, rowID) // extracted rows as CSV
fmt.Println(item.Status, "
", csv) run.rs
use writ_client::{RunOptions, WritAgent};
let agent = WritAgent::discover().await?; // find the running daemon
let workflows = agent.workflows().list().await?;
let wf = &workflows.data[0];
let outcome = agent.workflows().run_and_wait(wf.id, &RunOptions::default()).await?;
let rows = agent.runs().data(outcome.run.row_id().unwrap()).await?;
println!("{} → {}: {}", wf.name, outcome.run.status, rows.data); Dónde se ejecuta una run decide su coste: tu agente local la ejecuta gratis; una ejecución cloud se descuenta del uso incluido de tu plan — consulta la facturación.
ciclo de vida ▸ ocho estados
El ciclo de vida de una ejecución.
Cada ejecución informa uno de ocho estados normalizados:
| Estado | Significado |
|---|---|
queued | Una ejecución cloud esperando un hueco — expone su posición en la cola y una estimación. |
pending | Dirigida a un agente de escritorio, esperando a ser recogida. Sin posición de cola — el agente tira cuando está listo. |
running | Los pasos se ejecutan en un navegador en vivo. |
repairing | La reparación con IA trabaja sobre el workflow. Un estado superpuesto mientras la reparación retiene el workflow, no un estado almacenado. |
success | La ejecución se resolvió y sus salidas están disponibles. |
failed | La ejecución se resolvió con error — el campo error dice por qué. |
cancelled | Detenida a petición antes de resolverse. |
skipped | No ejecutada — por ejemplo, retenida por su propia configuración. |
queued vs pending: queued es del lado cloud (se abrirá un hueco; puedes ver tu posición). pending es de escritorio (tu agente recoge la ejecución cuando se conecta) — no tiene posición de cola que mostrar.
El feed de ejecuciones unifica cinco tipos en un solo flujo — workflow, check, ai_session, automation y crawl — todo lo que se ejecutó aparece en un mismo lugar, con los mismos estados.
Eventos en vivo
Mientras una ejecución corre, el progreso paso a paso llega en stream por SSE — cada SDK lo expone en su idioma nativo:
events.ts
for await (const ev of client.runs.events(runRowId(run))) {
console.log(ev.type, ev);
} events.py
for ev in client.runs.events(run_row_id(run)):
print(ev["type"], ev) events.go
for ev, err := range client.Runs.Events(ctx, rowID) {
if err != nil { break }
fmt.Println(ev.Type, ev)
} events.rs
use futures_util::StreamExt;
use writ_client::RunEvent;
let mut events = agent.runs().events(run_id).await?;
while let Some(ev) = events.next().await {
match ev? {
RunEvent::Step { index, step_type, status, .. } => println!("{index} {step_type} {status}"),
RunEvent::Finished { status, .. } => println!("done: {status}"),
_ => {}
}
} límites ▸ por plan
Cuánto puede durar una ejecución.
Cada plan fija una duración máxima de ejecución. Una run que alcanza su tope se detiene y se resuelve como failed — no puede facturar sin fin.
| Plan | Duración máx. de ejecución |
|---|---|
| Free | 2 min |
| Starter | 4 min |
| Pro | 5 min |
| Growth | 10 min |
| Scale / Enterprise | 15 min |
Las sesiones de grabación en cloud tienen su propio tope: 10 minutos en Free, hasta 60 minutos en Scale y Enterprise. Las sesiones de streaming se limitan aparte — consulta la referencia de streaming.
reparación ▸ ia opcional
Reparación con IA.
Los sitios cambian. Con ai_repair_enabled en un workflow (desactivado por defecto), una ejecución que rompe por un selector obsoleto dispara una reparación en lugar de simplemente fallar. La reparación opera en dos niveles:
| Reparación de selector | El selector se vuelve a derivar sobre la página en vivo; un candidato validado sustituye al obsoleto y el paso se reintenta en el sitio. |
| Regrabación con base real | Para cambios estructurales, un navegador en vivo recorre el flujo de nuevo y la receta se regraba a partir de lo que funciona realmente ahora. |
La reparación siempre corre en el servicio de IA gestionado en la nube y se mide por los tokens que usa — nunca con una clave BYO.
Mientras un workflow se repara queda bloqueado: las demás ejecuciones en cola del mismo workflow se retienen hasta que la reparación termina, para que no fallen todas en el mismo paso roto.
Cada workflow conserva sus últimas 50 entradas de reparación, cada una etiquetada con repair_type selector o rerecord — puedes auditar exactamente qué cambió y por qué.
Fallo honesto por defecto. Sin el flag, un selector roto hace fallar la ejecución y lo dice. No hay cadena silenciosa de selectores de respaldo ni «autocuración» sin IA — una ejecución reproduce la receta tal como se grabó, o la reparación (activada) la corrige a la vista.
siguiente ▸ a dónde ir
Sigue adelante.
- Referencia de pasos — cada tipo de paso, sus campos y un ejemplo real.
- AI sessions — la vía de describir: un objetivo dentro, un workflow grabado fuera.
- Managed endpoints — convierte este workflow en un endpoint REST; MCP lo hace una herramienta para agentes.
- Facturación y uso — exactamente cómo se mide una ejecución cloud.