Documentation / Exploitation / Guides pratiques / Manage workflow storage

Manage workflow storage

Workflow and agent definitions live in a definition store, backed by PostgreSQL — in every environment, development included. Edits made in the console survive redeployments, are shared across proxy replicas, and are versioned: immutable published versions plus an active pointer per definition, a single mutable draft, optimistic concurrency, instant rollback.

Git does not lose its place: it stays the language (YAML), the seed and the archive — see the two sections below.

Point it at a database

Set DEFINITION_STORE_URL on the endpoint and proxy (postgres://…). It may be the same database as the run index (RUN_DB_URL) — the tables are disjoint — and that is what happens by default: with DEFINITION_STORE_URL unset, a Postgres RUN_DB_URL is used. With neither, boot fails with an explicit message rather than starting half-configured.

Locally, docker compose up -d postgres provides it; the compose file publishes it on host port 5433 (not 5432) so it cannot collide with another Postgres already running on the machine — override with POSTGRES_PORT.

There used to be a file:<dir> driver serving the repository's YAML directly. It was removed before any production use: having no versions and no draft, it left half the product behind a capabilities.versions flag that reached into the editor, and two drivers meant two chances to diverge silently.

The engine itself never reads the store at run time: each run's spec is journaled in its Restate invocation, so replay is pinned regardless of later edits. Sub-workflows follow the same rule — when a run starts, the proxy resolves every workflow the graph can call (transitively) and pins those specs into the invocation too. Two consequences worth knowing:

  • a workflow that exists only in the store (created in the console, never written to workflows/) is callable as a sub-workflow;
  • a child's version is frozen at the parent run's start, so publishing a new version of a sub-workflow leaves runs already in flight untouched.

Saving from the console re-grafts the previous version's YAML comments onto the new spec: the editor carries only the structure, and those comments carry the why — without this, the first console save would erase what the seed brought over from git.

Seed a fresh store from git

On boot, if the store is empty, the proxy imports every definition from the seed roots as published v1: the host's system definitions (DEFINITION_SEED_DIR, default apps/api — only agent-invoke.workflow.yaml lives there), plus every directory listed in the instance manifest's seed: field — this is how shipped content stays instance data rather than host code (the clinical demos live in content/clinical-demo, seeded by seed: [content/clinical-demo]; the Docker image embarks content/). Nothing happens once the store holds any definition — a live store is never overwritten.

Seed without publishing: drafts/

Files under workflows/drafts/ or agents/drafts/ are seeded as drafts — never published, so they never route. Use it for bench fixtures and work-in-progress specs that must ship with the seed without claiming an event type. The slug comes from the file's base name, not its path, so moving a file into drafts/ keeps its identity — and a file with the same base name at the root and in drafts/ is refused at boot. The boot log reports the two populations separately (published vs. drafts).

Editing YAML by hand: DEFINITION_SEED_ALWAYS

Set it to 1 and the proxy re-publishes the seed directory at every boot, so the development loop stays what it always was: edit a YAML, restart, it is live. It is idempotent by content hash — a file identical to the active version publishes nothing, so ten restarts do not create ten versions. A drafts/ file follows the same rule against the current draft (never the active version), and is still never published.

Only ever set this in development. Anywhere definitions are edited in the console, it would overwrite them on every restart.

Export back to git

The store is the live truth; git remains the archive and review channel:

pnpm --filter @meridian/api run definitions:export -- ./definitions-export   # active versions → YAML
pnpm --filter @meridian/api run definitions:import -- ./some-dir             # publish as NEW versions

Import never overwrites history — each file becomes a new published version. Use export/import to back up, review changes in a PR, or promote definitions between environments.

Roll back a bad publish

Rolling back moves the active pointer to an earlier published version — instant, no redeploy, and in-flight runs are unaffected (their spec is journaled). Authors do it from the workflow view (see Publish and roll back), or via the API: POST /api/workflows/<slug>/rollback {"to": N}.

Multi-replica behavior

Each proxy replica keeps an in-memory routing cache and polls the store's generation counter (≤ every 3 s): a publish on one replica reaches the others within seconds.

75 documents7 sectionssource : /docs · généré au build