Local workflow runner · Rust · YAML-driven

Local workflows,
declared in YAML.

Define your jobs in a YAML file, run them locally, trace every event in JSONL — zero external infrastructure.

Install → See how it works
workflow.yml
id: deploy-app
version: 1  schema_version: 1
steps:
  - id: build
    type: command
    run: cargo build --release
  - id: wait-ready
    type: sleep
    duration: 2s
  - id: run-tests
    type: command
    run: cargo test --all
YAML-driven JSONL event store DAG workflow engine Isolated workspaces Plugin system SQLite projections .flowpkg packages Rust natif Zero infra ▶ Open Source YAML-driven JSONL event store DAG workflow engine Isolated workspaces Plugin system SQLite projections .flowpkg packages Rust natif Zero infra ▶ Open Source
Comment ça marche

Du YAML au run en 3 étapes.

📝
Créer YAML
Valider
📦
Enregistrer
Lancer
📋
Consulter logs
01

Définis ton workflow

Crée un fichier workflow.yml avec un name, une version et une liste de steps. Valide-le en une commande.

$ flow validate workflow.yml
02

Enregistre et exécute

Enregistre le job, lance-le. RunFlow crée un workspace isolé et émet chaque événement en JSONL.

$ flow job add workflow.yml
$ flow job run demo
03

Consulte les runs

Liste tes runs, lis les logs JSONL, consulte les manifests de complétion et nettoie les anciens runs avec la rétention.

$ flow run logs <run_id>
Fonctionnalités

Local-first. Event-driven.

⚙️

DAG workflow engine

Exécution de steps ordonnés : command, sleep, wait_until, plugin.

📄

JSONL event store

Chaque événement de run est écrit en JSONL. Historique complet et lisible.

🧾

Run manifests

Chaque run terminé produit manifest.json avec statut final, timestamps, policy et métriques.

🗂️

Workspaces isolés

Chaque run dispose de son propre workspace dans .flow/, ignoré par Git.

🔌

Système de plugins

Génère des squelettes Rust, Java, Python, Node. Valide les manifests.

📦

.flowpkg packages

Build et installe des packages JSON avec workflow YAML et checksum déterministe.

🗄️

SQLite projections

Runs et jobs projetés en SQLite pour des requêtes rapides.

🧹

Rétention des runs

Supprime les anciens runs et snapshots avec dry-run, limite de conservation et seuil d'âge.

Format YAML

Minimal. Expressif.

Seul name est obligatoire pour créer un draft. version et schema_version valent 1 par défaut, steps vaut []. Pour run/test/package, il faut au moins un step.

Types de steps supportés :

command sleep wait_until plugin
workflow.yml — complete example
# draft minimal valide
name: draft-job

# workflow exécutable
name: backup-db
version: 1
schema_version: 1
steps:
  - name: dump
    type: command
    run:
      command: echo
      args: ["backup"]

  - name: pause
    type: sleep
    duration: 2s

  - name: notify
    type: plugin
    plugin_id: notifier
    run:
      command: notifier-plugin
Commandes CLI

Tout piloté depuis le terminal.

Workflow
flow validateValide un workflow YAML (schema v1)flow validate workflow.yml
flow migrateValide et indique si une migration est requiseflow migrate workflow.yml
flow versionAffiche la versionflow version
Jobs
flow job addEnregistre un workflow YAML (upsert)flow job add workflow.yml
flow job updateMet à jour un job existantflow job update workflow.yml
flow job deleteSupprime un job par IDflow job delete demo
flow job clearSupprime tous les jobsflow job clear
flow job listListe les jobs enregistrésflow job list
flow job showAffiche le workflow YAML source d'un jobflow job show demo
flow job runExécute directement ou met en queue si le daemon tourneflow job run demo
flow testTeste un job (--verbose)flow test demo --verbose
Runs & Logs
flow run listListe tous les runs et leur statutflow run list
flow run showAffiche un run (state source) depuis .flow/flow run show <run_id>
flow run logsLit les events JSONL; stdout/stderr sont dans logs/<run_id>flow run logs <run_id>
flow run summaryAffiche le résumé workflow depuis logs/flow run summary <run_id>
flow run outputAffiche stdout ou stderr d'un stepflow run output <run_id> ping_1111
flow run cancelAnnule une queue ou tue le process daemon actifflow run cancel <run_id>
Steps manuels
flow step retryRejoue un stepflow step retry <run_id> <step_name>
flow step restartRelance un step (reset + retry)flow step restart <run_id> <step_name>
flow step resetRéinitialise un step en état PENDINGflow step reset <run_id> <step_name>
flow step skipSaute un stepflow step skip <run_id> <step_name>
flow step rerun-fromRepart depuis un stepflow step rerun-from <run_id> <step_name>
Plugins & Packages
flow plugin initGénère un squelette (rust/java/python/node)flow plugin init rust ./my-plugin
flow plugin validateValide un manifest de pluginflow plugin validate manifest.json
flow plugin inspectAffiche un manifest normalisé (résumé)flow plugin inspect manifest.json
flow plugin testExécute un plugin avec PluginInput isoléflow plugin test "cmd" input.json
flow plugin listListe les plugins installés dans .flow/pluginsflow plugin list
flow package buildBuild un .flowpkg JSON avec checksumflow package build workflow.yml
flow package installValide puis installe un package .flowpkgflow package install demo.flowpkg
Registry
flow registry scanScanne les manifests locaux et génère plugins.jsonflow registry scan
flow registry scan --checkVérifie que le registry versionné est à jourflow registry scan --check
flow registry list pluginsListe les plugins enregistrésflow registry list plugins
flow registry inspectInspecte un plugin enregistréflow registry inspect ssl_check
flow registry exportExporte le contexte compact pour intégrations externesflow registry export --for-agent
Daemon
flow daemon startDémarre le daemon et enqueue les jobs schedulésflow daemon start
flow daemon statusAffiche le statut réel (queue, run actif, heartbeat)flow daemon status
flow daemon stopArrêt propre (stop request + wait)flow daemon stop
flow daemon restartRestart propre (stop + start)flow daemon restart
Preview schedules
flow schedule nextPreview uniquement: affiche les prochaines dates d'une expression cronflow schedule next "0 */5 * * * * *"
--countNombre d'exécutions à afficherflow schedule next "0 */5 * * * * *" --count 3
--fromDate UTC de départ pour le calculflow schedule next "0 */5 * * * * *" --from 2026-05-31T14:00:00Z
flow schedule workflowPreview uniquement: lit schedule: dans un workflow YAMLflow schedule workflow workflow.yml
Rétention
flow retention runScanne ou purge les anciens runsflow retention run --dry-run --keep-runs 20
--older-than-daysNe supprime que les runs plus anciens que ce seuilflow retention run --keep-runs 20 --older-than-days 30
Installation

En ligne en quelques minutes.

git clone https://github.com/dandyArise/runflow.git
Set-Location .\runflow
cargo build --release
.\target\release\flow.exe version

Optionnel : ajouter le répertoire release à votre PATH utilisateur.

$bin = (Resolve-Path .\target\release).Path
[Environment]::SetEnvironmentVariable("Path", [Environment]::GetEnvironmentVariable("Path","User")+";$bin","User")
git clone https://github.com/dandyArise/runflow.git
cd runflow
cargo build --release
./target/release/flow version

Sans installation globale : cargo run -- version

Guides

Exemples pas à pas.

Workflow ping local

Objectif : lancer un ping vers 1.1.1.1 et récupérer stdout/stderr et les métadonnées du step via RunFlow.

# workflow.yml
name: ping-cloudflare
version: 1
schema_version: 1

steps:
- name: ping_1111
type: command
run:
command: ping
args: ["-n", "4", "1.1.1.1"]

Sur Linux/macOS, utilisez args: ["-c", "4", "1.1.1.1"].

flow job add .\workflow.yml
$runId = flow job run ping-cloudflare
flow run summary $runId
flow run output $runId ping_1111
flow run output $runId ping_1111 --stderr

Les fichiers sont aussi disponibles directement dans logs/ et .flow/.

Get-Content ".\logs\$runId\ping_1111\stdout.log"
Get-Content ".\logs\$runId\ping_1111\step.metadata.json"
Schedules et preview

Le bloc schedule du workflow configure l'exécution automatique par le daemon. Les commandes flow schedule servent seulement à prévisualiser les prochaines dates.

schedule:
cron: "0 */5 * * * * *"
timezone: Europe/Paris
enabled: true

Format cron : sec min hour day-of-month month day-of-week year. Sans schedule, ou avec schedule: false / enabled: false, le job reste exécutable manuellement mais le daemon ne le planifie pas.

Le raccourci schedule: "0 */5 * * * * *" reste supporté et équivaut à timezone UTC + enabled true.

Preview CLI : ces commandes ne lancent rien, elles affichent seulement les prochaines dates calculées.

flow schedule next "0 */5 * * * * *" --count 5
flow schedule next "0 */5 * * * * *" --from 2026-05-31T14:00:00Z --count 3
flow schedule workflow .\workflow.yml

Exemples : 0 0 * * * * * = toutes les heures, 0 */10 * * * * * = toutes les 10 minutes, 0 30 9 * * Mon * = chaque lundi à 09:30 UTC.

Statut actuel

Ce qui marche, ce qui arrive.

✅ Fonctionnel

CLI complet S6
Validation de schéma YAML
Workflows draft avec name seul
JSONL event store
Manifests de complétion
Moteur d'exécution local
Workspaces isolés
stdout/stderr capturés sans redirection shell
Métadonnées workflow et step dans logs/
Projections SQLite
Rétention runs/snapshots
Packages .flowpkg avec checksum
Daemon long-running avec queue, statut et schedules cron
Cancel réel avec kill du process tree
Plugin test avec workspace isolé
Registry local versionné avec scan --check
Preview cron avec flow schedule next
Release Windows automatique sur tag

🔧 Limitations connues

Pas encore de workers distribués
Plugins locaux uniquement pour l'instant