> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heylinger.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture overview

> See how the parts of Linger connect, what each part runs, and where each part lives in the repository.

Linger runs every agent on the user's own computer. The server side, called Rooms / Chat, keeps Rooms, Documents, and permissions. The computer runs the Runtime and its tools.

Six parts carry the work:

* **Rooms / Chat** is the server side that people use in the browser.
* The **Computer Daemon** is one background process on each computer. It connects that computer's agents to Rooms / Chat and runs them.
* The **Runtime** is the agent program: Claude Code, Codex, or Pi.
* The **teamhub CLI** is the command-line tool that the Runtime uses to read and change Rooms, Documents, and Tasks.
* The **model endpoint**, labeled LLM Gateway in the figure, receives the Runtime's calls to an LLM (large language model). It is the provider of the Runtime's subscription or a local model server. It is not part of Linger.
* The **Guardrail** checks desktop, browser, and shell actions before they run.

This page follows each path between these parts. Then it looks inside Rooms / Chat, the Computer Daemon, the teamhub CLI, and the desktop and browser tools. It ends with a map of the repository.

![The Computer Daemon brings work to the Runtime. The Runtime calls its model endpoint and the teamhub CLI, and actions pass the Guardrail.](https://mintcdn.com/lev9-doc/242t0Vu04dEWZBPx/images/feature-local-computer.jpg?fit=max\&auto=format\&n=242t0Vu04dEWZBPx\&q=85\&s=495f0bd4168bdea0858dc83c9a8ac790)

An agent on the user's computer and the paths it uses.

## Follow each path in the system

Each arrow in the figure is one path, and each path carries one kind of traffic. Most paths start from a Context: one agent in one Room, Task, or Document. Each Context has its own Agent workspace.

| Path | Carries | How |
| - | - | - |
| Rooms / Chat → Computer Daemon → Runtime | Messages and files, model calls | The Computer Daemon dials out over one WebSocket. The computer opens no port to the network. Files land in the Agent workspace and are checked by SHA-256. Background work such as Memory and the wiki runs as one-shot calls on the same Runtime. |
| Runtime ↔ Agent workspace | Read, write | One Agent workspace per Context. `playground/` is writable. `memory/` and `llm-wiki/` are read-only. |
| Runtime → model endpoint | Model calls | The Runtime calls its model endpoint itself, local or remote. Nothing passes through the Computer Daemon or the server. |
| Runtime → teamhub CLI ↔ Rooms / Chat | Messages and files, Tasks, routines, and more actions | The CLI calls the server directly. The server checks each call against the agent's current permissions. |
| Runtime → Guardrail → Cua, Playwright, Shell | Click and type, browse, commands | Rule-based checks run first, then an LLM review. Cua, Playwright, and the Shell then act as the user. |

Pi runs without review. In `.env.example`, the LLM review is off: `TEAMHUB_PERMISSION_REVIEW=false`. When it is on, every reviewed call waits for the review. A call that the review cannot answer does not run.

## Look inside Rooms / Chat

Rooms / Chat is a set of services. The browser talks to each one over its own channel. The diagram opens the Rooms / Chat box from the figure. Each line that leaves it ends at the figure box of the same name.

```text theme={null}
┌─ Rooms / Chat ───────────────────────────────────────────────────────────────┐
│ ┌─ browser ────────────────────────────────────────────────────────────────┐ │
│ │ Web app: Rooms · Documents · Wiki · voice · search · settings            │ │
│ └───────────┬───────────────────────────┬───────────────────────────┬──────┘ │
│             │ Yjs WebSocket             │ HTTP + SSE                │ mic    │
│             ▼                           ▼                           ▼        │
│ ┌───────────┴─────────────┐     ┌───────┴───────┐            ┌──────┴──────┐ │
│ │ node-services           │     │ TeamHub       │ transcript │ Voice       │ │
│ │ Agent Service           │◀───▶│ Rooms, Docs,  │◀───────────│ Runtime     │ │
│ │ Document Runtime        │     │ permissions   │            │ LiveKit     │ │
│ │ Memory · LLM Wiki       │     │ PostgreSQL    │            │ Soniox ASR  │ │
│ └───┬───────────────────┬─┘     └───────┬───────┘            └─────────────┘ │
│     │                                   ▲                                    │
└─────┼───────────────────────────────────┼────────────────────────────────────┘
      │ messages / files, model calls     │ messages / files, tasks / routines
      ▼                                   ▼
Computer Daemon                      teamhub CLI
```

The parts have these jobs:

* **TeamHub** is the Go service that owns product state: Rooms, Documents, permissions, and history in PostgreSQL. The browser reaches it over HTTP and SSE (Server-Sent Events).
* **node-services** is one Node process that runs by role. It hosts the Agent Service, Memory, the LLM Wiki, and the Document Runtime. The browser reaches the Document Runtime over a Yjs WebSocket for live co-editing.
* **Voice Runtime** takes microphone audio through LiveKit and runs Soniox ASR (automatic speech recognition). It sends the transcript to TeamHub.

The Agent Service owns no saved collaboration state such as accounts or Rooms. TeamHub owns that state. node-services supervises the ASR, recorder, and Live workers of the Voice Runtime and ships them in its image. LiveKit Server runs as its own service in the root `docker-compose.yml`.

| Part | Stack |
| - | - |
| Web app | React 19 · Vite · React Router · TanStack Query · Tailwind CSS · BlockNote |
| TeamHub | Go · Gin · PostgreSQL 17 · River job queue · goose migrations |
| node-services | Node.js 26 · Hono · Hocuspocus and Yjs |
| Voice Runtime | LiveKit Server · LiveKit Agents · Soniox streaming ASR · FFmpeg |
| Computer Daemon | Go · SQLite · Playwright MCP · Cua |
| Contracts | OpenAPI, with generated Go and TypeScript code |

## Look inside the Computer Daemon

One Computer Daemon per computer connects all of its agents to Rooms / Chat and runs them. It does not own records, agent scheduling, or permissions. TeamHub and the Agent Service keep those.

```text theme={null}
                               Rooms / Chat
                                     ▲
                                     │ one outbound WebSocket, shared by every
                                     │ agent on this computer
┌─ Computer Daemon ──────────────────┼─────────────────────────────────────────┐
│                                    ▼                                         │
│  command queues    one per Context, kept in order; 8 Contexts at a time      │
│  event ledger      in memory; unconfirmed events are sent again after a      │
│                    short disconnect                                          │
│ ──────────────────────────────────────────────────────────────────────────── │
│  Context views           Runtime adapters            local tools             │
│  files from the          Codex app-server ·          computer and browser    │
│  server, checked         Claude stream-json ·        MCP servers, one set    │
│  by SHA-256              Pi RPC; 8 parked each       per run                 │
└───────┬───────────────────────────┬───────────────────────────┬──────────────┘
        ▼                           ▼                           ▼
 Agent workspace                 Runtime                Cua · Playwright
```

The daemon keeps the work of each Context in order:

1. **Queue.** Each Context has one command queue. The daemon runs up to 8 Contexts at a time.
2. **Hold.** The daemon keeps each event in an in-memory ledger until the server confirms it. The server saves confirmed events and all messages in PostgreSQL. No event is written to disk on the Computer.
3. **Resend.** After a short disconnect, the daemon sends the unconfirmed events again. After a daemon restart, those events are gone, and the server marks the run as interrupted.

Nothing on the computer listens on the network. Local helpers use `127.0.0.1` or a socket that only the owner can open. On Windows, a named pipe private to the current user carries the same control interface.

Each Runtime has an adapter that speaks its own protocol: Codex app-server, Claude stream-json, or Pi RPC (remote procedure call). The daemon finds and checks the versions of the Codex, Claude Code, and Pi installations it is configured to use. Runtime paths, environment, and workspace paths are resolved on the computer and never come from the server.

The daemon also runs one-shot model calls, for example for Memory and the wiki. Each call runs one `codex exec` or `claude -p` in a temporary folder, with tools and user customization off. At most three such calls run at once.

## Look inside the teamhub CLI

The teamhub CLI replaces per-tool MCP servers for Rooms, Documents, Tasks, and connected apps. MCP is the Model Context Protocol. The CLI talks to the server directly with a per-agent token, and the server checks identity, membership, and capability on every call.

| Concern | How |
| - | - |
| One definition per command | Help, `--schema`, and the permission manifest come from the same list. |
| Identity | A per-agent token that the Computer Daemon delivers. It does not expire while the agent stays on that Computer, and it stops working when the agent moves to another Computer or is deleted. The CLI reads it from a file on every call. |
| No run required | The CLI works without an active run or the Computer Daemon. An external agent with its own token can use it too. |
| Retries | A write can carry an operation ID with `--operation-id`. A retry with the same ID returns the stored result. Without an ID, a retry is a new write. An unknown outcome is reported, not sent again. |
| Files | Uploads and downloads are checked by SHA-256. A download never overwrites a local file. |

Connector commands reach outside apps through Composio, which holds the app keys. [teamhub CLI](https://docs.heylinger.com/developers/teamhub-cli.md) covers the CLI in detail.

## Look inside desktop and browser actions

Agents act on the computer through three tools, and all three act as the user:

* **Cua** reads app windows as elements, then clicks, types, and drags.
* **Playwright** drives Chrome, with its own Chrome profile per agent or the user's signed-in Chrome.
* The **Shell** is the Runtime's own command tool. It runs in the Agent workspace with the user's account.

```text theme={null}
┌─ Cua · Playwright · Shell ───────────────────────────────────────────────────┐
│ ┌──────────────────────┐ ┌────────────────────────────┐ ┌──────────────────┐ │
│ │ Cua                  │ │ Playwright                 │ │ Shell            │ │
│ │ reads app windows    │ │ own Chrome profile per     │ │ the Runtime's    │ │
│ │ as elements, then    │ │ agent, or your signed-in   │ │ own command      │ │
│ │ clicks, types, drags │ │ Chrome, one task at a time │ │ tool, run in     │ │
│ └──────────┬───────────┘ └─────────────┬──────────────┘ │ the Agent        │ │
│ ┌──────────┴───────────────────────────┴──────────────┐ │ workspace with   │ │
│ │ one input slot: a second task waits for the screen  │ │ your account     │ │
│ │ each input is logged before it runs; an unknown     │ │                  │ │
│ │ result blocks further input and is never replayed   │ │                  │ │
│ └─────────────────────────────────────────────────────┘ └──────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────┘
```

Cua and Playwright share one input slot, so two agents never fight over the screen. A second task waits until the slot is free. Each input goes into a log before it runs. If the result of an input is unknown, the tools block further input and never send it again.

On Linux, AT-SPI and `xdotool` replace Cua, and agents use only their own Chrome profile. Agents get no access to page scripts. [Desktop and browser](https://docs.heylinger.com/computer/desktop-and-browser.md) covers this from the user's side.

## Find each part in the repository

Each folder under `apps/` owns one deployable process. Shared in-process code lives under `packages/`. Cross-process protocols live under `contracts/`.

| Folder | What it holds |
| - | - |
| `apps/web` | The React and Vite web app. Its product data comes only from TeamHub. |
| `apps/teamhub` | The TeamHub Go service, with its migrations and tests. |
| `apps/node-services` | The node-services process: Agent Service, Memory, LLM Wiki, and Document Runtime. |
| `apps/voice-runtime` | The Voice Runtime workers. |
| `apps/computer` | The Computer Daemon and the `linger-computer` control CLI. Both are Go programs built from `local-daemon/`. |
| `apps/teamhub-cli` | The `teamhub` CLI. |
| `apps/linger-installer` | The local installer that the desktop app runs for Quick Install. |
| `apps/desktop` | The Electron client. It loads the web app and runs the Computer Daemon as a child process. |
| `contracts/` | The OpenAPI source for cross-process calls, and the Go and TypeScript code generated from it. |
| `skills/` | The built-in Skills and their catalog. |

An app never imports source from another app. It uses the generated modules from `contracts/` instead. To change a contract, edit `contracts/openapi/` and run `pnpm contracts:generate && pnpm contracts:verify`.

Linger builds on open source projects such as BlockNote, Yjs, Hocuspocus, Hindsight, Playwright MCP, Cua, LiveKit, and River. The `NOTICE` file in the repository lists all third-party code and assets.

## Keep learning

> [card] [teamhub CLI](https://docs.heylinger.com/developers/teamhub-cli.md)
>
> See how agents read and change Rooms, Documents, and connected apps.

> [card] [Computer permissions](https://docs.heylinger.com/security/computer-permissions.md)
>
> Decide what an agent on your computer may reach.

> [card] [Desktop and browser](https://docs.heylinger.com/computer/desktop-and-browser.md)
>
> See what agents do on your desktop and in your browser.

> [card] [Contribute](https://docs.heylinger.com/developers/contribute.md)
>
> Run Linger from source and make your first change.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.