Overview
The technical entry to the architecture. The plain-language version of this story is How it works; this page names the actual decisions and parts, then points at the pages that go deep.
One decision drives everything
An agent is data, not a process. Its config, memory, chats and knowledge are rows and files in storage. While nobody talks to it, nothing runs and nothing costs anything.
The rest of the architecture is consequences of that one decision:
- The brain is ephemeral. There is no "agent server". The
apiloads the agent's data, becomes that agent for one turn — the LLM loop runs here — and lets go. Thousands of agents, zero idle cost. - The hands are ephemeral. When a turn needs a real computer (bash, files, a browser), the brain spins up a
worker— a WORKERED k8s Job that runs the task and disappears. No LLM, no memory, no secrets inside. - All state lives outside compute. Postgres, Redis, object storage and LightRAG hold everything; any brain or worker run picks up exactly where the last one stopped.
- Capabilities plug in over MCP. Tools, knowledge and memory attach to the brain through one standard socket — the brain stays small, and what an agent can do is configuration, not code.
The picture

Read it bottom-up: the bottom line is the agent; the two boxes above it are disposable compute that briefly animates it.
One image, two roles
api is a single NestJS codebase and image playing both roles:
- Core — the always-on control plane: HTTP API, auth, teams, billing, admin.
- Brain — the same image executing an agent turn ("runtime" in these docs =
apirun ephemerally, per turn).
One image because a turn touches the same domain the Core owns — agents, chats, memory, quotas, billing. Splitting them would mean duplicating that domain across two services; instead the role is decided by how the code is invoked, and there is exactly one thing to build, version and deploy.
What deploys
| Part | Role | Lifecycle |
|---|---|---|
api | Core control plane + the agent brain (one image) | always on; brain work per turn |
worker | the hands — worker (bash · fs · browser), an ephemeral MCP server | per task, stops on idle |
app / admin | customer cabinet / admin panel (Nuxt) | always on |
| Postgres · Redis · object storage · LightRAG | all state: agents & chats, queue & events, artifacts, knowledge | always there |
The repository
One monorepo — github.com/Agentfy/agentfy — holds the whole platform:
agentfy/
├── api/ NestJS — Core + brain (one image); slices/ = 8 layered groups
├── worker/ the hands — worker image (bash · fs · browser)
├── app/ Nuxt — customer cabinet
├── admin/ Nuxt — admin panel
├── k8s/ Helm charts + ArgoCD app-of-apps (GitOps)
├── terraform/ cluster & cloud infrastructure (IaC)
└── docs/ this documentation site (VitePress)The backbone invariant
Inside api, the code is CleanSlice vertical slices in 8 strictly layered groups — infra → setup → system → user → admin → runtime → agent → billing — and dependencies point only downward, no cycles. The orchestrator (the brain's loop) sits in the agent group and reaches down into the mechanisms; nothing reaches up. That single rule keeps the backend untangled as it grows.
→ Go deep: Layered slices (the groups & the rule) · Slice breakdown (every sub-slice) · Runtime model (a turn end to end).