S’exécute surWrit CloudDesktopAuto-hébergé
Sur cette page
Workflows.
Un workflow est une liste ordonnée d’étapes qui s’exécute dans un vrai navigateur et renvoie des données structurées. Créez-le une fois — en l’enregistrant ou en le décrivant — puis exécutez-le à la demande, sur planification, depuis un webhook, ou comme endpoint publié et MCP tool.
Writ s’exécute sur vos propres comptes, avec vos propres identifiants et données, sur les sites que vous êtes autorisé à utiliser.
objet ▸ la forme
L’objet workflow.
Un workflow est du JSON simple : un nom, un tableau steps ordonné, et les entrées déclarées par défaut contre lesquelles ses placeholders se résolvent. Chaque étape est un petit objet avec un type et une 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
} étapes ▸ le vocabulaire
30+ types d’étapes.
Les étapes s’exécutent dans l’ordre, et chacune peut lire ce que les précédentes ont produit. Le vocabulaire couvre navigation, interaction, attentes, extraction, onglets, IA, authentification et contrôle de flux — chaque type est listé dans la référence des étapes avec ses champs, un exemple réel et son comportement.
Navigation
Interaction
Attentes
Extraction
Onglets
IA
Authentification
Flux
io ▸ entrées et sorties
Des entrées, des données structurées en sortie.
Une exécution transporte ses entrées dans le champ de corps form_data. Dans les valeurs des étapes, les placeholders se résolvent à l’exécution — la recette reste générique et rien de sensible n’y est stocké :
| Placeholder | Se résout en |
|---|---|
{{key}} | La clé correspondante du form_data de l’exécution, à défaut les valeurs par défaut enregistrées du workflow. |
{{vault:name}} | Un secret de votre coffre, injecté à l’exécution. Les secrets sont une interpolation dans la valeur d’une étape — jamais une étape à part. |
{{extracted:key}} | Une valeur extraite par une étape précédente de la même exécution — pour chaîner des requêtes api_call. |
{{file:slot}} | Un fichier stocké lié à l’emplacement nommé (imports, téléchargements capturés). |
En sortie, les étapes extract remplissent extracted_data et l’exécution se règle avec result_data — la charge structurée que lit votre appelant.
exécuter ▸ l’api
Exécuter un workflow.
Un seul endpoint lance une exécution. Par défaut, l’appel attend le verdict ; désactivez wait pour récupérer immédiatement un identifiant de tâche.
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": { "…": "…" } } | Paramètre de requête | Rôle |
|---|---|
wait | true par défaut — l’appel HTTP bloque jusqu’au règlement de l’exécution. |
timeout | Durée d’attente, en secondes. 120 par défaut, plage acceptée 10–300. |
Avec wait=false, la réponse est {"task_id", "status": "pending", "workflow"} — interrogez l’exécution, ou abonnez-vous à ses événements.
Depuis les SDKs
Sur votre propre machine, les SDKs publiés découvrent l’agent local et exécutent le même workflow sans frais de calcul :
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); L’endroit où une exécution a lieu décide de son coût : votre agent local l’exécute gratuitement ; une exécution cloud est décomptée de l’utilisation incluse de votre plan — voir la facturation.
cycle de vie ▸ huit statuts
Le cycle de vie d’une exécution.
Chaque exécution rapporte l’un de huit statuts normalisés :
| Statut | Signification |
|---|---|
queued | Une exécution cloud en attente d’un créneau — elle expose sa place dans la file et une estimation. |
pending | Dirigée vers un agent desktop, en attente d’être récupérée. Pas de position de file — l’agent tire quand il est prêt. |
running | Les étapes s’exécutent dans un navigateur en direct. |
repairing | La réparation IA travaille sur le workflow. Un état superposé pendant que la réparation retient le workflow, pas un statut stocké. |
success | L’exécution est réglée et ses sorties sont disponibles. |
failed | L’exécution s’est réglée en erreur — le champ error dit pourquoi. |
cancelled | Arrêtée sur demande avant son règlement. |
skipped | Non exécutée — par exemple retenue par sa propre configuration. |
queued vs pending : queued est côté cloud (un créneau va s’ouvrir ; vous voyez votre position). pending est lié au desktop (votre agent récupère l’exécution quand il se connecte) — il n’a pas de position de file à montrer.
Le fil des exécutions unifie cinq types dans un même flux — workflow, check, ai_session, automation et crawl — tout ce qui s’est exécuté apparaît au même endroit, avec les mêmes statuts.
Événements en direct
Pendant l’exécution, la progression étape par étape est diffusée en SSE — chaque SDK l’expose dans son idiome natif :
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}"),
_ => {}
}
} limites ▸ par plan
Combien de temps une exécution peut durer.
Chaque plan fixe une durée maximale d’exécution. Une exécution qui atteint son plafond est arrêtée et se règle en failed — elle ne peut pas facturer indéfiniment.
| Plan | Durée max d’exécution |
|---|---|
| Free | 2 min |
| Starter | 4 min |
| Pro | 5 min |
| Growth | 10 min |
| Scale / Enterprise | 15 min |
Les sessions d’enregistrement cloud ont leur propre plafond : 10 minutes sur Free, jusqu’à 60 minutes sur Scale et Enterprise. Les sessions de streaming sont plafonnées à part — voir la référence streaming.
réparation ▸ ia en opt-in
Réparation IA.
Les sites changent. Avec ai_repair_enabled sur un workflow (désactivé par défaut), une exécution qui casse sur un sélecteur périmé déclenche une réparation au lieu de simplement échouer. La réparation opère à deux niveaux :
| Réparation de sélecteur | Le sélecteur est re-dérivé sur la page en direct ; un candidat validé remplace le sélecteur périmé et l’étape est retentée sur place. |
| Réenregistrement ancré | Pour les changements structurels, un navigateur en direct rejoue le parcours et la recette est réenregistrée à partir de ce qui fonctionne réellement. |
La réparation s’exécute toujours sur le service IA cloud managé et est décomptée selon les tokens utilisés — jamais sur une clé BYO.
Pendant la réparation, le workflow est verrouillé : les autres exécutions en file du même workflow sont retenues jusqu’à la fin de la réparation, pour ne pas toutes échouer sur la même étape cassée.
Chaque workflow conserve ses 50 dernières entrées de réparation, chacune étiquetée repair_type selector ou rerecord — vous pouvez auditer exactement ce qui a été changé et pourquoi.
Échec honnête par défaut. Sans le drapeau, un sélecteur cassé fait échouer l’exécution et le dit. Il n’y a pas de chaîne de sélecteurs de repli silencieuse ni d’« auto-guérison » sans IA — une exécution rejoue la recette telle qu’enregistrée, ou la réparation (activée) la corrige au grand jour.
suite ▸ où aller
Continuez.
- Référence des étapes — chaque type d’étape, ses champs et un exemple réel.
- sessions IA — la voie « décrire » : un objectif en entrée, un workflow enregistré en sortie.
- Managed endpoints — transformez ce workflow en endpoint REST ; MCP en fait un outil pour agents.
- Facturation & utilisation — exactement comment une exécution cloud est décomptée.