Concept 7 of 10

Two agents on one repo. Workspace intact.

Run a second agent on the same repo without the two clobbering each other. Point five agents at one repo and they overwrite each other's edits and corrupt the tree. Flowgate makes the collision impossible — the runtime owns the shared state and hands out only non-overlapping work.

The runtime owns the context, not the model

Workflow state lives in a shared store the runtime owns — the coordination state about the repo, sitting alongside the working tree rather than inside any one agent's head. Each agent receives only the slice relevant to its current step. The shared truth is in one place, which is what makes running more than one agent on the same repo tractable at all. (For where this state lives and how you run it, see how you run flowgate.)

No agent acts on a stale read

Agent B won't silently overwrite agent A's fix. Every read returns the workflow version, and a write must echo it back as expectedVersion. If another agent moved the state in between, the write is rejected with STALE_WORKFLOW_VERSION and the fresh version comes back — so the agent re-reads and retries instead of clobbering work it never saw. Optimistic concurrency, enforced by the runtime.

wire.jsonl
→ flowgate.command  { "transition": "edit", "expectedVersion": 7, ... }

← { "error": { "code": "STALE_WORKFLOW_VERSION",
               "message": "expected version 7, current is 9" },
    "workflow": { "version": 9 } }   // re-read, then retry

Two agents can't hold the same files at once

A transition declares the files it will write with owned_files. Before it runs, the runtime takes a global lock on them — across every workflow running against the repo; the repo is the protected unit — and releases it when the step finishes. If another agent already holds one of those files, this one doesn't fail and doesn't stomp: it durably suspends with status waiting_on_lock and auto-resumes the moment the files free, in FIFO order — even across a restart. A dead holder's lock is reaped on a TTL, so nothing deadlocks.

refactor.yaml
editing_auth:
  transitions:
    apply_patch:
      target: verifying
      executor:
        kind: agent
        owned_files: ["src/auth.rs", "src/session.rs"]   # locked globally for this step

A second agent reaching for src/auth.rs while it's held doesn't get an error — it gets parked and woken when the file is free:

wire.jsonl
← { "result": { "status": "waiting_on_lock" },
    "context": { "_lock_wait": { "files": ["src/auth.rs"] } } }

# … the holder finishes, the file frees, and this workflow auto-resumes (audit: lock.resumed)

Run the independent work in parallel

Once the work is partitioned into non-overlapping pieces, fan it out. The parallel executor runs N branches concurrently and aggregates them under a join condition — all, any, or at_least: K.

review.yaml
executor:
  kind: parallel
  branches:
    - { kind: workflow, definitionId: review-security }
    - { kind: workflow, definitionId: review-perf }
    - { kind: workflow, definitionId: review-style }
  join: { at_least: 2 }
  max_concurrency: 4

Concept 7 of 10

Next concept →

One shared vocabulary

A lexicon so the model, your workflows, and your team mean the same thing by the same word.

See all concepts