AbstractFlow — Architecture (Current)¶
Updated: 2026-05-26 Scope: describes implemented behavior in this repository (no roadmap claims).
AbstractFlow is a workflow authoring + orchestration layer in the AbstractFramework ecosystem. For the browser editor, Flow is Gateway-first: AbstractGateway owns discovery, persistence, run execution, ledgers, artifacts, media, and the Runtime/Core deployment stack. AbstractFlow keeps optional local Runtime/Core compatibility for Python hosts and development.
See also: ../README.md, getting-started.md, api.md, faq.md, visualflow.md, web-editor.md, cli.md.
Repository layout (what ships where)¶
abstractflow/ # Published Python package
__init__.py # Public API exports
core/flow.py # Flow IR re-export (from AbstractRuntime)
runner.py # FlowRunner (runtime-backed)
compiler.py # Compiler shim (delegates to AbstractRuntime)
visual/ # VisualFlow models + portable execution wiring
adapters/ # Adapter re-exports (delegates to AbstractRuntime)
cli.py # `abstractflow` CLI
workflow_bundle.py # Bundle helpers (delegates to AbstractRuntime)
docs/ # Human docs (this folder)
web/ # Reference visual editor app
backend/ # Legacy/dev FastAPI host + Gateway proxy
frontend/ # React editor + Gateway-first run UI
flows/ # Default flow storage when running backend from `web/`
runtime/ # Default runtime persistence in a source checkout (installed: ~/.abstractflow/runtime)
tests/ # Test suite
High-level data and execution flow¶
flowchart LR
subgraph Authoring
FE[web/frontend<br/>React editor] -->|/api/gateway/*| GW[AbstractGateway<br/>VisualFlows + bundles + runs + media]
GW -->|persists| GWDATA[(Gateway data dirs)]
end
subgraph Execution
HOST[Host process<br/>(Gateway / CLI / 3rd party)] -->|validate| VF[VisualFlow models<br/>abstractflow/visual/models.py]
HOST -->|create_visual_runner| WIRE[Runtime wiring<br/>abstractflow/visual/executor.py]
WIRE --> RT[AbstractRuntime Runtime<br/>tick/resume]
RT --> STORES[(RunStore / LedgerStore / ArtifactStore)]
RT -->|LLM_CALL, TOOL_CALLS| AC[AbstractCore integration]
RT -->|START_SUBWORKFLOW| REG[WorkflowRegistry]
end
FE -->|HTTP/SSE: start/commands/ledger| GW
Portable data model: VisualFlow JSON¶
The portable authoring format is VisualFlow (Pydantic models):
- VisualFlow, VisualNode, VisualEdge, NodeType, PinType, …
Evidence: ../abstractflow/visual/models.py.
Key portability rule (enforced by design): the JSON must contain enough configuration to execute outside the web backend. Hosts may add storage, auth, and UI around it, but execution should remain host-independent.
Compilation and execution (portable)¶
VisualFlow → Flow IR¶
AbstractFlow delegates “VisualFlow → Flow IR” semantics to AbstractRuntime:
- abstractflow.visual.executor.visual_to_flow() calls abstractruntime.visualflow_compiler.visual_to_flow(...).
Evidence: ../abstractflow/visual/executor.py.
Flow IR → WorkflowSpec¶
AbstractFlow delegates compilation to AbstractRuntime:
- abstractflow.compiler.compile_flow is re-exported from abstractruntime.visualflow_compiler.compiler.
Evidence: ../abstractflow/compiler.py.
Running (FlowRunner)¶
FlowRunner owns host-friendly execution convenience:
- creates a default in-memory runtime when you don’t provide one
- normalizes outputs to {"success": bool, "result": ...} for callers
- can auto-drive nested SUBWORKFLOW waits in non-interactive contexts
Evidence: ../abstractflow/runner.py, tests in ../tests/test_runner.py.
VisualFlow execution wiring (host responsibilities)¶
The key host entrypoint is:
- abstractflow.visual.executor.create_visual_runner(...)
It wires the runtime based on what is present in the flow tree:
- registers subflows/agent workflows when needed (workflow registry)
- enables artifact storage when memory nodes are present
- wires AbstractCore effect handlers when LLM/tool nodes are present
- optionally installs AbstractMemory KG effect handlers when memory_kg_* nodes are present
Evidence: ../abstractflow/visual/executor.py.
Session-scoped events (VisualSessionRunner)¶
VisualFlows that include custom events (on_event / emit_event) are executed with a session-aware runner:
- VisualSessionRunner starts derived event-listener workflows as child runs in the same session.
- During run(), it also ticks those child runs so EMIT_EVENT branches make progress without a separate host loop.
Evidence: ../abstractflow/visual/session_runner.py, wiring in ../abstractflow/visual/executor.py, tests in ../tests/test_visual_custom_events.py.
Web editor host (Gateway-first)¶
The modern editor is a thin Gateway client:
- VisualFlow CRUD: GET/POST/PUT/DELETE /api/gateway/visualflows
- Publish: POST /api/gateway/visualflows/{flow_id}/publish
- Run input schema: GET /api/gateway/bundles/{bundle_id}/flows/{flow_id}/input_schema
- Runs/commands: POST /api/gateway/runs/start, POST /api/gateway/commands
- Replay/stream: GET /api/gateway/runs/{run_id}/ledger, GET /api/gateway/runs/{run_id}/ledger/stream
- Artifacts: GET /api/gateway/runs/{run_id}/artifacts/...
The static @abstractframework/flow server, Vite dev proxy, and Python FastAPI
host all proxy /api/gateway/* and inject Gateway auth server-side because
browser EventSource cannot send custom auth headers. Flow injects the opaque
Gateway browser session from an HTTP-only Flow cookie; server/admin Gateway
tokens do not create browser login state. The Flow connection form asks for
Gateway user id and token, then validates that the token resolves to that user
before accepting the login. The raw token is exchanged for Gateway session
cookies server-side, and the connection response does not return Gateway session
ids or CSRF tokens to browser JavaScript. Gateway owns the user's runtime
mapping and returns it as read-only principal metadata. Different browsers can
connect to the shared Gateway as different principals. Remote browsers may
provide a token for the server-configured Gateway URL, but may not change the
Gateway URL unless
ABSTRACTFLOW_ALLOW_REMOTE_BROWSER_GATEWAY_CONFIG=1 is enabled. Flow uses the
request Host header for that check by default; set
ABSTRACTFLOW_TRUST_PROXY_HEADERS=1 only behind a reverse proxy that strips
client-supplied forwarded headers.
Gateway media and catalog contracts¶
The editor discovers generated media support from Gateway capabilities rather
than local Runtime/Core imports:
- assistant.media.generated_image
- assistant.media.edited_image
- assistant.media.generated_video
- assistant.media.image_to_video
- assistant.media.generated_voice
- assistant.media.generated_music
Gateway catalog endpoints can return gateway_catalog_v1 (catalog metadata +
canonical items) or older legacy arrays/maps. The frontend adapter normalizes
both and uses those catalogs for image, video, voice, transcription, and music
provider/model selectors. Video selectors use Gateway's task-scoped vision
catalogs (text_to_video and image_to_video) instead of hardcoded model lists.
Gateway common.readiness (gateway_surface_readiness_v1) is consumed as a
surface-level readiness overlay for optional media/model-residency UX. It does
not replace endpoint descriptors, because Flow still needs those descriptors to
construct the actual Gateway requests.
Native media authoring nodes are persisted as native VisualFlow node types:
generate_image, edit_image, image_to_image, generate_video,
text_to_video, image_to_video, generate_voice, generate_music,
transcribe_audio, and listen_voice. Gateway progress callbacks emitted as
abstract.progress ledger events are rendered as running-node progress rather
than terminal step output, which keeps long video generations observable without
closing the active node. Old saved music flows that used the temporary
browser-side lowering are normalized back to native generate_music when loaded
or saved.
Legacy/dev FastAPI host¶
The reference host in web/ is now a Gateway proxy/static host by default. When
ABSTRACTFLOW_ENABLE_LOCAL_RUNTIME=1 is set, it also provides compatibility routes for:
- Flow CRUD (web/backend/routes/flows.py) storing ./flows/*.json relative to its working dir
- Durable stores for runs/ledger/artifacts (web/backend/services/runtime_stores.py)
- WebSocket execution (web/backend/routes/ws.py) with message types:
- { "type": "run", "input_data": {…} }
- { "type": "resume", "response": "…" }
- { "type": "control", "action": "pause|resume|cancel", "run_id": "…" }
These local routes remain for development/reference compatibility only. The normal browser editor
path uses /api/gateway/* and Gateway's run/ledger/artifact contracts. See
web-editor.md for current run instructions.
Workflow bundles (.flow)¶
WorkflowBundles package a root VisualFlow JSON plus any referenced subflows into a single .flow (zip) file (manifest + flow JSON files).
- CLI:
abstractflow bundle pack|inspect|unpack(abstractflow/cli.py) - Implementation delegates to AbstractRuntime:
abstractflow/workflow_bundle.py - Format/packing semantics are owned by AbstractRuntime; AbstractFlow is a thin wrapper.
Evidence: ../tests/test_workflow_bundle_pack.py, ../abstractflow/workflow_bundle.py.
What AbstractFlow owns vs delegates¶
Owns in this repo
- VisualFlow schema (abstractflow/visual/models.py)
- Host wiring helpers (abstractflow/visual/executor.py, abstractflow/visual/session_runner.py)
- Public runner conveniences (abstractflow/runner.py)
- Reference web editor app (web/)
- CLI wrapper (abstractflow/cli.py)
Delegates to AbstractRuntime
- Compilation semantics and builtins (abstractflow/compiler.py, abstractflow/visual/builtins.py)
- Adapter implementations (abstractflow/adapters/*)
- WorkflowBundle format and IO (abstractflow/workflow_bundle.py)