
# How it works

## Hosts

```text
people ─┐
        ├─► your TLS proxy or tunnel ─► Acahti control plane ─► Runner
agents ─┘
```

| Host | Runs |
|---|---|
| Control plane | The gateway image `ghcr.io/benchyard/acahti`, Forgejo, Woodpecker server, and PostgreSQL, in Docker Compose under `~/acahti`. No pipelines run here |
| Runner | One Woodpecker agent that executes jobs. Parallelism follows the host's CPU and memory |

## The gateway

The Go gateway is the only public application. The web app, MCP, and the REST API all call one internal catalog, so every surface sees the same data and the same permissions.

| Path | Client | Backend |
|---|---|---|
| `/ui/*` | People in the browser | Catalog |
| `/mcp` | IDE agents | Catalog |
| `/acahti/v1` | CLI, scripts | Catalog |
| `/<org>/<repo>.git` | Git | Proxied to Forgejo as the authenticated user |
| `/api/packages/*` | npm, pip, uv | Proxied to Forgejo as the authenticated user |
| `/hooks/*` | Forgejo, Woodpecker | Index updates and live events |

Lists, the Board, and navigation read from the gateway's own index in PostgreSQL, which kernel webhooks keep current. File contents, diffs, and step logs are read live from the kernels.

## Pipelines

A push or pull request triggers Woodpecker. Before a job starts, the gateway expands its YAML: official pipes become `acahti-pipe` calls, named secrets become environment, and publishing pipes get the identity of the person who triggered the run. Results flow back through webhooks into the index, where `checks_wait`, the Inbox, and the Board read them. See [Pipelines](/docs/pipelines/).

## Data

All state is under `ACAHTI_DATA` as bind mounts. Once data exists, never run `docker compose down -v`.

| Directory | Contents |
|---|---|
| `postgres/` | Databases for Forgejo, Woodpecker, and the gateway |
| `forgejo/` | Git repositories and Forgejo state |
| `woodpecker/` | Woodpecker server state |
| `gateway/` | Invites, OAuth clients, access tokens, module files |

Back up PostgreSQL and `ACAHTI_DATA` before every upgrade.

## Optional modules

`ACAHTI_MODULES` turns on extra product areas. All are off by default; a disabled module creates no tables, shows no tab, and its APIs answer 404.

| Module | Adds | Data |
|---|---|---|
| `work` | Tickets, todos, and documents | `work_*` tables, `gateway/work/` |
| `argos` | A browser for Argos test runs; CI links runs to pipelines | `argos_*` tables, `gateway/argos/`; ingest with `ARGOS_TOKEN` |
| `chat` | Org chat with a dock in the web app | `chat_*` tables |

Agents see enabled modules in `whoami.modules`.
