Architecture overview

This is the operator's view. For the user-facing summary, see Introduction → Architecture.

Planes

The platform splits into three planes:

PlanePurposeExamples
Control planeStores desired state. Reconciles toward it.Agents, Agents Orchestrator, Runners, Organizations.
Data planeServes runtime traffic.Gateway, Threads, Chat, Files, LLM, LLM Proxy, Secrets, Notifications, Tracing, Authorization, Identity, Users, Apps Service, Media Proxy, Ziti Management, Token Counting, Metering.
WorkloadsAgent pods provisioned on demand by the orchestrator.Runtime container + agynd + MCP sidecars + Ziti sidecar.

Services

Control plane

ServiceResponsibility
AgentsStores agent definitions and sub-resources (MCPs, skills, hooks, ENVs, init scripts, volumes, attachments). Publishes agent.updated events when configuration changes.
Agents OrchestratorReconciler. Watches threads with unacked messages, selects an eligible runner, calls StartWorkload. Enforces idle timeout. Cleans up. Leader-elected via Kubernetes Lease.
RunnersCentral registry of runners (cluster + org scopes) and runtime workload state. Reconciles container status via InspectWorkload calls to each runner.
OrganizationsOrg CRUD, membership lifecycle, invites. Owner of org-level authorization tuples.

Data plane

ServiceResponsibility
GatewaySingle external API. Speaks ConnectRPC, gRPC, gRPC-Web from one handler. Authenticates every request.
ChatBuilt-in web/mobile chat experience. Wraps Threads with product behavior (unread counts, activity status).
ThreadsGeneric conversation storage. Type-agnostic participants. Publishes message.created.
FilesFile upload, metadata, pre-signed URLs. S3-backed.
LLMProvider + model registry. Resolves model name → provider endpoint + auth + remote name.
LLM ProxyOpenAI-compatible Responses API (and Anthropic Messages API) for agents. Auth, resolve, forward, meter.
SecretsLocal secrets (encrypted at rest) and remote-provider secrets (Vault, etc.). Resolves on workload start.
NotificationsReal-time event fanout. Redis pub/sub backend. Socket.IO external, gRPC internal.
TracingOTLP span ingestion. Upsert semantics for in-progress spans. Per-LLM-call full context capture.
AuthorizationThin proxy in front of OpenFGA. Centralizes config, adds observability.
IdentityCentral identity_id ↔ identity_type registry. Nickname uniqueness per org.
UsersUser records, profiles, API tokens, devices. Provisions users on first OIDC login.
Apps ServiceApp definitions, installations, profiles, enrollment, audit log.
Ziti ManagementAll OpenZiti Controller interactions. Identity, service, policy CRUD.
MeteringSingle store for usage records (LLM tokens, compute, storage, activity). Dedup by idempotency_key.
Token CountingProvider-accurate tokenization for cost reporting.
Media ProxyAuthenticated media serving. SSRF protection. Image downsampling. Range requests for video/audio.

Workloads

Each agent pod contains:

  • Runtime container — runs agynd, which runs the agent CLI.
  • MCP server sidecars — one per MCP attached to the agent. Same pod network, accessed over localhost.
  • Hook sidecars — one per hook configured.
  • Init container — copies agynd, the agyn CLI, and the agent CLI binary into the runtime container.
  • Ziti sidecar — provides OpenZiti tunnels for outbound calls to Gateway, LLM Proxy, and Tracing.

Data stores

StoreUsed byNotes
PostgreSQLThreads, Users, Identity, Organizations, Agents, Runners, Tracing, Apps Service, MeteringTypical pattern: one Postgres cluster, one database per service. Tracing is the highest-volume database.
OpenFGAAuthorizationBacked by its own PostgreSQL database.
RedisNotifications (pub/sub), short-lived cachesA single in-cluster or managed Redis is enough.
S3-compatible object storageFilesOne dedicated bucket. Lifecycle policies optional.
Persistent VolumesAgent state (per-volume per-thread instances)Each PVC is ReadWriteOnce.

Lifecycle: a user message ends up as agent output

sequenceDiagram
  participant U as User
  participant CW as Chat Web
  participant GW as Gateway
  participant CH as Chat
  participant TH as Threads
  participant N as Notifications
  participant O as Orchestrator
  participant R as Runner
  participant A as Agent pod
  participant LP as LLM Proxy
  participant LM as LLM provider

  U->>CW: Type and send message
  CW->>GW: SendMessage
  GW->>CH: route
  CH->>TH: SendMessage
  TH->>N: publish message.created
  N-->>O: notification
  O->>R: StartWorkload (if needed)
  R->>A: pod created
  A->>GW: subscribe + GetUnackedMessages
  A->>LP: POST /v1/responses
  LP->>LM: forward
  LM-->>LP: response
  LP-->>A: response
  A->>GW: SendMessage (agent's reply)
  GW->>TH: persist
  TH->>N: publish message.created
  N-->>CW: notification
  CW-->>U: render

Internal vs. external authorization

  • External calls (Gateway): OpenFGA-checked via the Authorization service.
  • Internal calls (Istio mesh): Istio AuthorizationPolicy gates them by ServiceAccount. The Orchestrator and Runner services have privileged internal RPCs that bypass OpenFGA — exposed only to specific ServiceAccounts.

This separation is important: the data plane is callable by any authenticated identity (subject to authorization); the control plane has internal-only methods (e.g. CreateWorkload on Runners) that only the Orchestrator can call.

Mixed responsibilities

A few services have both control- and data-plane responsibilities:

  • Runners — registration (control) + workload state queries (data). The Console reads workload state for monitoring; the Orchestrator writes workload state for reconciliation.
  • Apps Service — app definitions (control) + installation event delivery (data).

Both are flagged in their service docs.

Repository map

RepositoryContains
agynio/apiProtobuf schemas for all services.
agynio/gatewayGateway service.
agynio/threadsThreads service.
agynio/chatChat service.
agynio/agentsAgents service.
agynio/agents-orchestratorReconciler.
agynio/runnersRunners service.
agynio/organizationsOrganizations service.
agynio/identityIdentity registry.
agynio/usersUsers service.
agynio/filesFiles service.
agynio/llmLLM service.
agynio/llm-proxyLLM Proxy.
agynio/secretsSecrets service.
agynio/notificationsNotifications service.
agynio/tracingTracing service.
agynio/authorizationAuthorization service + OpenFGA model + Terraform.
agynio/meteringMetering service.
agynio/token-countingToken counting service.
agynio/media-proxyMedia proxy.
agynio/ziti-managementZiti Management service.
agynio/appsApps Service.
agynio/k8s-runnerDefault Kubernetes runner.
agynio/agynd-cliAgent wrapper daemon.
agynio/agyn-cliPlatform CLI.
agynio/agn-cliNative agent loop.
agynio/files-mcpBuilt-in file-access MCP.
agynio/agent-init-{codex,claude,agn}Init images.
agynio/console-appConsole UI.
agynio/chat-appChat UI.
agynio/tracing-appTracing UI.
agynio/remindersReminders app.
agynio/telegram-connectorTelegram bridge app.
agynio/terraform-provider-agynTerraform provider.
agynio/bootstrapBootstrap — k3d + Terraform stacks. Source of install today.
ghcr.io/agynio/charts/*Per-service Helm charts (OCI). Consumed by bootstrap today.
agynio/platform-chartsCentralized umbrella chart, in preparation. Will replace per-service deployment in bootstrap once stable.

See Reference → Service catalog for a customer-facing version of the same list.