FlowDoc: the interchange format

A FlowDoc is one JSON file per flow or module. It is Amazon Connect Flow language, extended with tokens and tool metadata that Connect ignores-by-removal at materialization time.

Structure

{
          "flowdoc": "0.3",
          "kind": "flow | module",
          "name": "inbound-main",
          "displayName": "optional, the name Connect shows when it is not name",
          "description": "optional, as Connect shows it",
          "connectType": "CONTACT_FLOW | CUSTOMER_QUEUE | ... | MODULE",
          "content": { "Version": "2019-10-30", "StartAction": "...", "Actions": [ ... ] },
          "layout": { "<actionId>": { "x": 0, "y": 0 } },
          "refs": [ { "token": "${cdref:queue:front-desk}", "type": "queue", "name": "front-desk" } ],
          "meta": { "generator": "core@0.3", "sourceHash": "sha256:...", "sourceKind": "ts | tf" }
        }
        

Invariants

  1. Deterministic: same inputs, byte-identical FlowDoc (stable key order, stable action ordering).
  2. Lossless for unknown blocks: any Action not modeled by the builder is preserved verbatim (GenericBlock) through studio edits and codegen.
  3. sourceHash ties the FlowDoc to the builder file it was generated from, for the watch-mode dirty guard and the studio's conflict check.
  4. A reference token occupies an entire field value, or, for a casefield, an entire map key or list item, and is never interpolated into a longer string. Connect requires the fields that hold references to be "either fully static or a single valid JSONPath identifier", so a partially substituted value is invalid. See conformance/flow-language/actions.md. (Restated to cover a key in 0.3, docs/adr/0008-case-field-ids.md.)
  5. No more than 250 Actions per flow, and Identifiers are unique, at most 50 characters, and exclude the characters Connect reserves. Enforced by conformance/schema/flowdoc-0.3.schema.json.

Versioning

flowdoc: "0.3" since 2026-10-05; 0.2 was the format from 2026-09-11 and 0.1 from 2026-08-30. Every version bump ships a migration in @flow-as-code/core plus fixtures: migrateFlowDoc reads any supported version and returns the current one, conformance/migrate/<case>/ holds an input at each older version and the exact bytes it becomes, and every reader (the CLI, the studio, the CDK construct, both Terraform emitters) migrates on the way in, so the rest of the code sees one version. 0.1 to 0.2 was a version bump alone: 0.2 added the view reference type, meta.sourceKind, and the optional description, none of which a 0.1 document could carry. 0.2 to 0.3 is the same: 0.3 added the tasktemplate, casetemplate, casefield, assistant and phonenumber reference types, all at once, because an older reader (npm 0.2.x, provider 0.1.x) refuses a document carrying a token it does not know, so each type added on its own would have been a release both repositories make in step (tasks/README.md, "Phase D", "Considered and not taken"). Adding a reference type is a version change by this precedent. The older schemas stay byte-identical, held by a hash in packages/core/src/conformance.test.ts, so a 0.1 or 0.2 file is still validated against the rules it was written to, and a per-type clause for a type modeled after 0.2 shipped goes into 0.3 only, encoding what the service enforces at create (owner decision 3 in tasks/README.md), so a 0.2 document the service accepted still validates after migration.

Contract artifacts