PageSourceSearch

https://prj-common-p-docs.web.app/assets/js/e9fe92a4.d6582b31.js

js prj-common-p-docs.web.app collected 2026-10-03 12:34:13 UTC 14,471 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocs=globalThis.webpackChunkdocs||[]).push([[2496],{73490(e,t,n){n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>a,toc:()=>c});const a=JSON.parse('{"id":"concepts/concepts-architecture","title":"Catalyst Architecture","description":"A summary of how the Catalyst control plane, data plane, and your applications fit together, and how a runtime API call flows end to end.","source":"@site/docs/concepts/architecture.mdx","sourceDirName":"concepts","slug":"/concepts/architecture","permalink":"/concepts/architecture","draft":false,"unlisted":false,"tags":[],"version":"current","lastUpdatedAt":1784321677000,"sidebarPosition":14,"frontMatter":{"id":"concepts-architecture","title":"Catalyst Architecture","description":"A summary of how the Catalyst control plane, data plane, and your applications fit together, and how a runtime API call flows end to end.","sidebar_label":"Architecture summary","sidebar_position":14,"slug":"/concepts/architecture"},"sidebar":"catalyst","previous":{"title":"Dapr APIs","permalink":"/concepts/dapr-apis"},"next":{"title":"Console","permalink":"/concepts/console"}}');var r=n(74848),s=n(28453);const o={id:"concepts-architecture",title:"Catalyst Architecture",description:"A summary of how the Catalyst control plane, data plane, and your applications fit together, and how a runtime API call flows end to end.",sidebar_label:"Architecture summary",sidebar_position:14,slug:"/concepts/architecture"},i="Catalyst architecture",l={},c=[{value:"The three layers",id:"the-three-layers",level:2},{value:"Catalyst control plane",id:"catalyst-control-plane",level:3},{value:"Catalyst data plane",id:"catalyst-data-plane",level:3},{value:"Your applications and agents",id:"your-applications-and-agents",level:3},{value:"How a request flows",id:"how-a-request-flows",level:2},{value:"How workflow state survives",id:"how-workflow-state-survives",level:2},{value:"See also",id:"see-also",level:2}];function h(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",hr:"hr",li:"li",mermaid:"mermaid",ol:"ol",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"catalyst-architecture",children:"Catalyst architecture"})}),"\n",(0,r.jsxs)(t.p,{children:["This page summarizes how Catalyst fits together once you have the ",(0,r.jsx)(t.a,{href:"/concepts",children:"core concepts"})," in hand. For the full self-hosted topology, see ",(0,r.jsx)(t.a,{href:"/operate/hosting/enterprise-self-hosted/system-architecture",children:"System Architecture"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Catalyst is a managed runtime for distributed applications, durable workflows, and AI agents, built on the open-source ",(0,r.jsx)(t.a,{href:"https://dapr.io/",children:"Dapr"})," runtime. Architecturally it has three layers: a ",(0,r.jsx)(t.strong,{children:"control plane"})," for management, a ",(0,r.jsx)(t.strong,{children:"data plane"})," where the runtime lives (executing API calls, orchestrating durable workflows, and persisting their state), and the ",(0,r.jsx)(t.strong,{children:"applications and agents"})," you run yourself. Where each layer lives depends on the ",(0,r.jsx)(t.a,{href:"/operate/hosting",children:"hosting model"}),", but the conceptual architecture is the same \u2014 Catalyst owns the runtime and the backing infrastructure, you own the code."]}),"\n",(0,r.jsx)(t.h2,{id:"the-three-layers",children:"The three layers"}),"\n",(0,r.jsx)(t.mermaid,{value:'---\ntitle: The three layers of Catalyst\n---\nflowchart TD\n  subgraph CP["Catalyst control plane"]\n    direction LR\n    API(Management API)\n    CONSOLE(Console)\n    CLI(CLI)\n  end\n  subgraph DP["Catalyst data plane"]\n    direction LR\n    PLAT(Platform services)\n    SERVERS(Dapr Servers)\n    INFRA[(Backing infrastructure)]\n    PLAT--\x3eSERVERS\n    SERVERS--\x3eINFRA\n  end\n  subgraph APPS["Your applications & agents"]\n    direction LR\n    APP(App)\n    AGENT(Agent)\n  end\n  CP-."reconcile config".->DP\n  APPS--\x3eDP'}),"\n",(0,r.jsx)(t.h3,{id:"catalyst-control-plane",children:"Catalyst control plane"}),"\n",(0,r.jsxs)(t.p,{children:["The control plane is the management surface. You interact with it through the Catalyst console, the ",(0,r.jsx)(t.code,{children:"diagrid"})," CLI, and the Catalyst control plane API. It stores resource definitions \u2014 apps, components, policies, projects, managed services \u2014 and reconciles them into the data plane. The control plane is never on the path of a runtime API call: configuration flows from control plane to data plane, but application payloads do n
1ot flow through it."]}),"\n",(0,r.jsx)(t.h3,{id:"catalyst-data-plane",children:"Catalyst data plane"}),"\n",(0,r.jsx)(t.p,{children:"The data plane is where every runtime API call from your applications terminates. It has three parts:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Platform services"})," \u2014 the services Catalyst runs to operate the data plane. The ",(0,r.jsx)(t.strong,{children:"Gateway"})," is the regional endpoint your applications connect to over TLS \u2014 it authenticates incoming requests and routes them to the Dapr Server that represents the calling app. It is composed of various internal services like the ",(0,r.jsx)(t.strong,{children:"Catalyst agent"})," which reconciles configuration from the control plane and configures every other service in the data plane."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Dapr Servers"})," \u2014 the runtime that executes your API calls. Workflow orchestrations, pub/sub fan-out, state reads and writes, service invocation, and the rest of the ",(0,r.jsx)(t.a,{href:"/concepts/dapr-apis",children:"Dapr APIs"})," run here. Each Dapr Server carries a ",(0,r.jsx)(t.a,{href:"https://spiffe.io/",children:"SPIFFE"})," identity and uses mTLS to communicate to other Dapr Servers or backing infrastructure."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Backing infrastructure"})," \u2014 the stores and brokers behind the APIs: the ",(0,r.jsx)(t.a,{href:"/concepts/managed-services",children:"managed Pub/Sub broker, managed key-value store, and managed workflow store"})," that Catalyst provisions for you, plus any ",(0,r.jsx)(t.a,{href:"/concepts/components",children:"bring-your-own components"})," you wire up (Redis, Kafka, Postgres, an LLM provider, and so on)."]}),"\n"]}),"\n",(0,r.jsx)(t.h3,{id:"your-applications-and-agents",children:"Your applications and agents"}),"\n",(0,r.jsxs)(t.p,{children:["Your application and agent code runs wherever you choose: containers, virtual machines, physical machines, or serverless functions. Catalyst never executes this code; it only authenticates calls from it and serves API responses back to it. Apps reach the data plane using a ",(0,r.jsx)(t.a,{href:"/develop",children:"Dapr SDK"})," for their language, or by calling the available HTTP or GRPC APIs directly."]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsxs)(t.p,{children:["Where each layer runs depends on the hosting model. On ",(0,r.jsx)(t.strong,{children:"Catalyst Cloud"})," and ",(0,r.jsx)(t.strong,{children:"Catalyst Enterprise: Dedicated"}),", Diagrid runs both planes; on ",(0,r.jsx)(t.strong,{children:"Self-Hosted"}),", Diagrid runs the control plane and you run the data plane in your own infrastructure; on ",(0,r.jsx)(t.strong,{children:"Air-Gapped"}),", both planes run in your infrastructure with no outbound connectivity to Diagrid. The layering does not change \u2014 only the trust and network boundaries between layers do. See ",(0,r.jsx)(t.a,{href:"/operate/hosting",children:"Hosting options"})," for the four topologies side by side."]}),"\n",(0,r.jsx)(t.h2,{id:"how-a-request-flows",children:"How a request flows"}),"\n",(0,r.jsxs)(t.p,{children:["Take the simplest case: an orders application saves an order to the ",(0,r.jsx)(t.a,{href:"/concepts/managed-services",children:"managed key-value store"}),". The application code is a single SDK call, but the request crosses several steps inside the data plane, with identity and policy enforced at every hop."]}),"\n",(0,r.jsx)(t.mermaid,{value:'---\ntitle: A state save through the data plane\n---\nflowchart LR\n  APP(Orders app)\n  SDK(Dapr SDK)\n  subgraph DP["Catalyst data plane"]\n    direction LR\n    GW(Gateway)\n    subgraph SERVER["Dapr Server"]\n      direction LR\n      POL{Policy gate}:::decision\n    end\n    COMP(kvstore component)\n    STORE[(Managed key-value store)]\n    GW--\x3ePOL\n    POL--\x3eCOMP\n    COMP--\x3eSTORE\n  end\n  APP--\x3eSDK\n  SDK--"TLS + app token"--\x3eGW\n\n  classDef decision stroke:#ed8936'}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"App \u2192 SDK."})," The application calls ",(0,r.jsx)(t.code,{children:"save_state"})," on the Dapr SDK. The SDK serialises the call into a Dapr HTTP or gRPC request."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"SDK \u2192 Gateway."}
1)," The SDK opens a TLS connection to the regional Catalyst Gateway and attaches the app API token the application bound at startup."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Gateway \u2192 Dapr Server."})," The Gateway authenticates the token, resolves it to an ",(0,r.jsx)(t.a,{href:"/concepts/identities",children:"app"}),", and routes the request to the Dapr Server that represents that app inside the data plane."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Policy gate."})," Before the Dapr Server reaches a component, the ",(0,r.jsx)(t.a,{href:"/concepts/policies",children:"policies"})," attached to the app are evaluated \u2014 access scoping, payload restrictions, rate limits. A request that fails policy is rejected here and never touches the backing store."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Component \u2192 backing infrastructure."})," The Dapr Server invokes the ",(0,r.jsx)(t.code,{children:"kvstore"})," component, which writes the value to the managed key-value store. The Dapr Server authenticates downstream with its own SPIFFE SVID over mTLS, so the call has a verifiable principal on both sides."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.strong,{children:"Response."})," The result returns up the same path: backing store \u2192 component \u2192 Dapr Server \u2192 Gateway \u2192 SDK \u2192 application."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"Two properties of this flow are worth holding on to:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.strong,{children:"control plane is never in the path"})," \u2014 even though the app, the component definition, and the policy rules all originate there, the data plane resolves them locally."]}),"\n",(0,r.jsxs)(t.li,{children:["The ",(0,r.jsx)(t.strong,{children:"identity model is end-to-end"}),": the application authenticates to the Gateway with its app API token, and the Dapr Server mutually authenticates downstream with its own SPIFFE identity, so no hop relies on a shared secret or an unauthenticated trust assumption. See ",(0,r.jsx)(t.a,{href:"/concepts/security",children:"Security"})," for the full identity model and trust-boundary breakdown."]}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:"The flow looks the same for any other Dapr API \u2014 publishing to a topic, invoking another app, calling an LLM through the conversation API, scheduling a job \u2014 only the component and backing infrastructure at the end of the chain change."}),"\n",(0,r.jsx)(t.h2,{id:"how-workflow-state-survives",children:"How workflow state survives"}),"\n",(0,r.jsx)(t.p,{children:"A workflow or AI agent is a regular application that calls the Dapr workflow API; the orchestration itself runs inside the Dapr Servers and its state lives in the Catalyst-managed workflow store, not in your application memory. Each step the workflow takes \u2014 an activity scheduled, an activity completed, a timer set, an external event received \u2014 is persisted as an event in the workflow's history before the next step proceeds."}),"\n",(0,r.jsxs)(t.p,{children:["If the Dapr Server or your application restarts, the workflow resumes by replaying its history from the managed store. Long-running workflows that wait days for a human approval or an external signal consume no compute while paused; they wake up when the event arrives, replay from history, and continue from the next step. The mechanics \u2014 event sourcing, deterministic replay, activities, child workflows \u2014 are covered in depth in ",(0,r.jsx)(t.a,{href:"/concepts/durable-execution",children:"Durable execution"}),"."]}),"\n",(0,r.jsx)(t.h2,{id:"see-also",children:"See also"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"/operate/hosting",children:"Hosting options"})," \u2014 the four hosting topologies and where each plane runs in each."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"/concepts/security",children:"Security"})," \u2014 trust boundaries, mTLS and SPIFFE identity, and the shared-responsibility split."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"/concepts/dapr-apis",children:"Dapr APIs"})," \u2014 the building-block API surface the data plane exposes."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"/concepts/identities",children:"Application Identities"})," \u2014 how IDs bind workloads to the data plane."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"/concepts/durable-execution",children:"Durable execution"})," \u2014 how workflow and agent state survives restarts."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"/concepts#dapr",children:"Dapr"})," \u2014 relationship between Catalyst and the open-source Dapr runtime."]}),"\n"]})]})}function d(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},28453(e,t,n){n.d(t,{R:()=>o,x:()=>i});var a=n(96540);const r={},s=a.createContext(r);function o(e){const t=a.useContext(s);return a.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),a.createElement(s.Provider,{value:t},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.