Skip to main content

4. Architecture

Next.js + CopilotKit
React UI ─► CopilotRuntime route
├─ GET /api/agents (from YAML) ─────► Loco app
└─ AG-UI HTTP + SSE ────────────────► Loco app

Loco app (one binary, three modes)
controllers: agui, agents, webhooks, documents ─┐
workers: ingest, drive_workflow ────────────────┼─► Platform (in SharedStore)
scheduler + tasks ──────────────────────────────┘
config/*.yaml + config/agents/** ─► boot: load, validate, compile ─► Platform

Platform ─► graph-flow graphs
─► llm crate ─► vLLM
─► documents crate ─► docling-serve
─► integrations crate ─► external APIs / MCP
Loco app ─► Postgres (data, pgvector, queue, checkpoints)
─► OTel Collector ─► Jaeger

Process modes (one image, chosen by command)​

CommandRunsUse
bo-app startHTTP serverAPI pods
bo-app start --workerQueue workersWorker pods
bo-app start --server-and-workerBothSmall deployments, development
bo-app schedulerCron jobs from YAMLOne replica
bo-app task <name> k:vOne-off taskOperations, CI
bo-app db migrate / bo-app doctorMigrations, health checksDeploy pipeline

The start flags --worker, --server-and-worker and --all are (source-verified).

Invoice sequence, including the approval pause and resume​

User (CopilotKit) → CopilotRuntime: upload invoice / "process INV-123"
CopilotRuntime → Loco app: POST /agui/invoice_v1 (threadId=t1, runId=r1)
Loco app → CopilotRuntime: RUN_STARTED
Loco app → graph-flow: run(session t1)
graph-flow → docling-serve: convert file (markdown + JSON)
graph-flow → vLLM: structured extraction (JSON schema from YAML)
graph-flow → Postgres: vendor + PO match, embeddings
Loco app → CopilotRuntime: STATE_SNAPSHOT / text events per step
graph-flow → Loco app: WaitingForInput (human.approval node)
Loco app → Postgres: insert approval (pending), audit
Loco app → CopilotRuntime: STATE_SNAPSHOT, MESSAGES_SNAPSHOT
Loco app → CopilotRuntime: RUN_FINISHED{outcome: interrupt, reason: confirmation}
User → CopilotRuntime: Approve
CopilotRuntime → Loco app: POST /agui/invoice_v1 (threadId=t1, runId=r2, resume[...])
Loco app → Postgres: idempotent approval upsert
Loco app → graph-flow: set context.approval, run
graph-flow → Accounting connector: post_bill (Idempotency-Key)
graph-flow → Postgres: audit log
Loco app → CopilotRuntime: RUN_FINISHED{outcome: success}

Deployment​

┌──────────────── docker-compose / k8s namespace ─────────────────┐
│ web (Next.js :3000) ──► server (bo-app start :8080) ──► postgres │
│ worker (bo-app start --worker) ──┘ ▲ │
│ scheduler (bo-app scheduler) ───────┘ │
│ server/worker ──► vllm-chat :8000 vllm-embed :8001 │
│ ──► docling-serve :5001 │
│ ──► otel-collector :4317 ──► jaeger :16686 │
│ config/ mounted read-only into server, worker, scheduler │
│ optional profile "llmobs": opik + valkey + seaweedfs │
│ optional profile "ap": activepieces-ce + valkey │
└──────────────────────────────────────────────────────────────────┘

Postgres holds business data, pgvector embeddings, the job queue and workflow checkpoints.