Skip to content

System flowcharts

This document breaks the agent into a few small Mermaid diagrams so they render cleanly in VS Code’s Markdown preview and are easier to reason about.

1) High-level overview

This shows the major subsystems and how requests enter the system (WebSocket, HTTP pages, GraphQL), plus the optional bridging/distributed components.

flowchart LR
    subgraph Clients["Clients / Integrations"]
        WebApp["FDC3 Web App (Browser)"]
        AdminUI["Admin UI (Browser)"]
        LaunchedApp["Launched App Process"]
        ExternalHandlerProc["External Handler Process"]
        Bridge["Desktop Agent Bridge (BCP/BMP)"]
        Etcd[(etcd)]
        Consul[(Consul)]
    end

    subgraph Runtime["Runtime (ASGI)"]
        Uvicorn["Uvicorn / ASGI Server"]
        FastAPI["FastAPI App (create_app)"]
        WS["WebSocket /ws"]
        HTTP["HTTP Pages (/admin, /diagnostics, ...)"]
        GQL["GraphQL /graphql (Strawberry)"]
    end

    subgraph Core["Core Services (shared singleton state)"]
        CoreServices["CoreServices singleton"]
        AppReg["AppRegistry"]
        ListenerStore["ListenerStore"]
        ChannelMgr["ChannelManager"]
        CtxRouter["ContextRouter"]
        IntentRes["IntentResolver"]
        PluginReg["PluginRegistry"]
        ExtReg["ExternalHandlerRegistry"]
    end

    subgraph Data["Storage"]
        Storage["SqliteStorage"]
        SQLite[(SQLite DB file)]
    end

    subgraph Launching["App Launching"]
        Launcher["SubprocessLauncher"]
    end

    subgraph Bridging["Desktop Agent Bridging (optional)"]
        BridgeClient["BridgeClient"]
        BridgeRouter["BridgeRequestRouter"]
    end

    subgraph Distributed["Distributed Events (optional)"]
        DistAdapter["DistributedLogAdapter"]
    end

    WebApp <--> WS
    ExternalHandlerProc <--> WS
    AdminUI --> HTTP
    AdminUI --> GQL

    Uvicorn --> FastAPI
    FastAPI --> WS
    FastAPI --> HTTP
    FastAPI --> GQL

    WS --> CoreServices
    GQL --> CoreServices
    GQL --> Storage

    Storage --> SQLite
    CoreServices --> AppReg
    CoreServices --> ListenerStore
    CoreServices --> ChannelMgr
    CoreServices --> CtxRouter
    CoreServices --> IntentRes
    CoreServices --> PluginReg
    CoreServices --> ExtReg

    Launcher --> LaunchedApp

    BridgeClient <--> Bridge
    BridgeClient --> BridgeRouter
    BridgeRouter --> CoreServices
    BridgeRouter --> Storage
    BridgeRouter --> Launcher

    DistAdapter -.-> Etcd
    DistAdapter -.-> Consul

2) WebSocket protocol phases (WCP → DACP)

The /ws endpoint starts in the WCP handshake/identity validation phase. Once validated, it transitions to the DACP phase for ongoing FDC3 operations.

sequenceDiagram
    autonumber
    participant Client as Browser App / Client
    participant WS as /ws WebSocket
    participant AC as AccessControlHandler
    participant WCP as WCPHandler
    participant DACP as DACPHandler
    participant Core as CoreServices

    Client->>WS: Connect
    WS->>AC: validate_connection(origin, user-agent)
    AC-->>WS: allow/deny
    alt denied
        WS-->>Client: close(1008)
    else allowed
        Client->>WCP: WCP1Hello
        WCP-->>Client: WCP3Handshake
        Client->>WCP: WCP4ValidateAppIdentity
        WCP->>Core: register_instance(appId, instanceId, instanceUuid)
        WCP-->>Client: WCP5ValidateAppIdentityResponse
        Note over WS,DACP: Connection now in DACP mode
        Client->>DACP: DACP requests (broadcast/open/find/raise...)
        DACP->>Core: route via listeners/channels/intent resolver
    end

3) Core services and message routing

This diagram focuses on how context and intents move through the in-memory core. The core is a singleton so WebSocket handlers, GraphQL, plugins, and background components all share the same state.

flowchart TB
    CoreServices["CoreServices singleton"]

    AppReg["AppRegistry<br/>instances + connection state"]
    ListenerStore["ListenerStore<br/>context/intent listeners"]
    ChannelMgr["ChannelManager<br/>channels + events"]
    CtxRouter["ContextRouter<br/>broadcast routing"]
    IntentRes["IntentResolver<br/>resolve + deliver intents"]
    PluginReg["PluginRegistry<br/>in-process intent plugins"]
    ExtReg["ExternalHandlerRegistry<br/>external process handlers"]

    CoreServices --> AppReg
    CoreServices --> ListenerStore
    CoreServices --> ChannelMgr
    CoreServices --> CtxRouter
    CoreServices --> IntentRes
    CoreServices --> PluginReg
    CoreServices --> ExtReg

    CtxRouter --> ListenerStore
    CtxRouter --> ChannelMgr
    CtxRouter --> AppReg
    IntentRes --> ListenerStore
    IntentRes --> AppReg

4) Storage + admin/GraphQL surfaces

Admin pages are static HTML templates, while GraphQL provides read/write access to app directory and launch config data plus observability over connected instances and channels.

flowchart LR
    AdminUI["Admin UI (Browser)"]
    HTTP["HTTP pages (/admin, /diagnostics, ...)"]
    Templates["Jinja2 templates"]
    GQL["GraphQL /graphql"]
    GraphQLSchema["Schema + resolvers"]
    Storage["SqliteStorage"]
    SQLite[(SQLite DB file)]
    Core["CoreServices"]

    AdminUI --> HTTP --> Templates
    AdminUI --> GQL --> GraphQLSchema
    GraphQLSchema --> Storage --> SQLite
    GraphQLSchema --> Core

5) Desktop Agent Bridging (experimental, optional)

When bridging is enabled, the agent maintains an outbound WebSocket connection to a Desktop Agent Bridge. Some outbound actions are forwarded best-effort, and inbound bridged requests are routed through the BridgeRequestRouter into local storage/core/launcher/connection manager.

flowchart LR
    subgraph Local["Local Desktop Agent"]
        DACP["DACPHandler"]
        BridgeClient["BridgeClient"]
        BridgeRouter["BridgeRequestRouter"]
        Core["CoreServices"]
        Storage["SqliteStorage"]
        Launcher["SubprocessLauncher"]
        ConnMgr["WebSocketConnectionManager"]
    end

    Bridge["Desktop Agent Bridge (BCP/BMP)"]

    DACP -. "forward broadcast / raiseIntent (targeted)" .-> BridgeClient
    BridgeClient <--> Bridge
    BridgeClient -. "inbound bridged requests" .-> BridgeRouter

    BridgeRouter --> Core
    BridgeRouter --> Storage
    BridgeRouter --> Launcher
    BridgeRouter --> ConnMgr

6) Distributed channel events (optional)

If a distributed adapter is configured, channel events are published to an external backend so multiple agent workers can observe each other’s channel activity. Local delivery still happens even if the adapter fails.

flowchart LR
    ChannelMgr["ChannelManager"]
    DistAdapter["DistributedLogAdapter\n(Noop/Etcd/Consul)"]
    Etcd[(etcd)]
    Consul[(Consul)]

    ChannelMgr -. "publish channel_events" .-> DistAdapter
    DistAdapter -.-> Etcd
    DistAdapter -.-> Consul
    DistAdapter -. "subscribe channel_events" .-> ChannelMgr