# Run an Autarcho worker

Autarcho is a decentralized inference network. Workers contribute compute by
serving **GGUF** text models (quantised llama.cpp-style LLMs — this is a
GGUF-only network; ONNX, SafeTensors, and multimodal formats are not supported).
In return, the network pays for verified work in **USDC on Solana mainnet**.

All public worker files live at <https://autarcho.com/workers/>:

| File                    | Purpose                                             |
| ----------------------- | --------------------------------------------------- |
| `docker-compose.yml`    | Worker stack (CPU by default)                       |
| `docker-compose.gpu.yml`| NVIDIA CUDA override, layered on top of the above   |
| `worker.env.example`    | Full annotated `.env` template                      |
| `install.sh`            | Installer — writes `.env` from the gateway bootstrap|
| `EULA.md`               | Worker licence, acceptable use, and data terms      |

Current release: **0.1.0**. The CPU image is
`ghcr.io/czeti/node:0.1.0`; GPU images use the matching `-cudaNN` tag. CUDA 75
(Turing) is the validated 0.1.0 GPU path. See
[Compute capability tags](#compute-capability-tags) for the full matrix.

Public gateway: <https://api.autarcho.com>

## Requirements

- **x86_64 Linux** host (ARM is not supported for this release).
- **Docker Engine** with the **Compose v2** plugin (`docker compose`, not the
  legacy `docker-compose`).
- **curl** and **jq** on the host for `install.sh` (the installer parses the
  gateway's bootstrap document).
- **16 GB RAM** baseline for the container memory limit.
- **20+ GB free disk** for the GGUF model cache (larger models need more).
- **Outbound-only** networking: TCP **443** (bootstrap fetch, receipt
  submission) and TCP **4001** (libp2p to the gateway). **No inbound ports.**
  No port forwarding, no public IP, no DNS record required — the worker dials
  out; the gateway never dials in.
- **A current host trust store.** The worker image carries its own audited CA
  bundle, but `install.sh` and `curl` on the host use the operating system's
  bundle. Keep it updated (see [Host trust store](#host-trust-store)).
- **No account, token, or allowlist step is required.** The worker pins the
  gateway by PeerId and joins on first start.
- For GPU workers additionally: a supported **NVIDIA driver** and
  **nvidia-container-toolkit**.

## Quickstart (CPU)

```sh
mkdir -p autarcho-worker && cd autarcho-worker
curl -fsSLO https://autarcho.com/workers/docker-compose.yml
curl -fsSLO https://autarcho.com/workers/docker-compose.gpu.yml
curl -fsSLO https://autarcho.com/workers/install.sh
chmod +x install.sh
./install.sh --wallet <SOLANA_PUBKEY>
docker compose pull
docker compose up -d
docker compose logs -f node
```

Replace `<SOLANA_PUBKEY>` with the Solana address that should receive this
worker's USDC payouts. This is required: the installer validates it and the
compose file refuses to start without it. It is a public address only — the
worker never needs the wallet's private key.

The installer displays the EULA and requires you to accept it before writing
`.env`. For unattended installs, pass `--accept-eula`; the accepted version,
document hash, and timestamp are recorded in `.env` as `EULA_VERSION`,
`EULA_SHA256`, and `EULA_ACCEPTED_AT`.

The installer fetches `<gateway>/bootstrap.json` and writes `.env` for you,
including `TAG`, `REGISTRY`, `GATEWAY_URL`, `GATEWAY_P2P_ADDR`,
`GATEWAY_PEER_ID`, and `WORKER_SOLANA_WALLET`. If you skip the installer you
can copy `worker.env.example` to `.env` and fill it in by hand instead.

Watch the logs until the node reports it has connected to the gateway. Model
weights are downloaded into the cache volume on first job, so the first
requests can take longer than steady state.

### Verify you are talking to the real gateway

The installer pins the gateway by PeerId. The public gateway's PeerId is:

```
12D3KooWPEc9EMvcNttN1G6CSkNQm4gLKT9LEE5uKBJrCS2Wz4nE
```

You can cross-check what the gateway announces:

```sh
curl -fsS https://api.autarcho.com/bootstrap.json
```

The installer verifies this PeerId and refuses a bootstrap response for a
different peer. For a custom gateway, pass `--expect-peer-id <PEER_ID>` with a
value obtained through a trusted, out-of-band channel; the installer will not
accept an arbitrary peer from bootstrap alone.

No gateway-side allowlist entry, invite, or shared token is needed to join.

### Host trust store

The worker container is self-contained and carries its own audited CA
bundle. The host tools that talk to the gateway (`curl`, the installer, and
any CLI you run outside Docker) use the host OS trust store.
Keep that store current, especially after CA incidents such as the eMudhra
`emSign ECC Root CA - G3` distrust in October 2026.

On Ubuntu/Debian:

```sh
sudo apt-get update
sudo apt-get install --only-upgrade ca-certificates
```

Verify the distrusted root is gone:

```sh
openssl crl2pkcs7 -nocrl -certfile /etc/ssl/certs/ca-certificates.crt \
  | openssl pkcs7 -print_certs -noout \
  | grep -c "emSign ECC Root CA - G3"
```

The result must be `0`. Do not use plain `grep` on the PEM bundle: it is
base64, so the subject name is not visible without parsing.

## GPU workers

GPU support requires the NVIDIA driver and nvidia-container-toolkit on the
host. `nvidia-smi` must work on the host before you proceed, and `docker info`
should list the NVIDIA runtime.

Install with GPU flags:

```sh
./install.sh --wallet <SOLANA_PUBKEY> --gpu --compute-cap 75
```

`--compute-cap` is the two-digit compute capability of your GPU **without the
dot** (e.g. `7.5` → `75`). The installer writes the matching CUDA image tag into
`.env`. The 0.1.0 public set includes the CPU image and the CUDA 75 image; see
[Compute capability tags](#compute-capability-tags) for the full matrix. Start
with the layered compose files:

```sh
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d
```

Use the same `-f … -f …` form for subsequent `pull`, `up -d`, and `logs`
commands on a GPU worker.

### Compute capability tags

| Compute cap | Architecture | Typical GPUs              | Image tag                      | Published |
| ----------- | ------------ | ------------------------- | ------------------------------ | --------- |
| 75          | Turing       | GeForce GTX 16xx, RTX 20xx| `ghcr.io/czeti/node:0.1.0-cuda75` | yes   |
| 80          | Ampere       | A100                      | `ghcr.io/czeti/node:0.1.0-cuda80` | no    |
| 86          | Ampere       | GeForce RTX 30xx          | `ghcr.io/czeti/node:0.1.0-cuda86` | no    |
| 89          | Ada          | GeForce RTX 40xx          | `ghcr.io/czeti/node:0.1.0-cuda89` | no    |
| 90          | Hopper       | H100 (data-center)        | `ghcr.io/czeti/node:0.1.0-cuda90` | no    |

The table shows which tags are in the 0.1.0 public set. If your GPU's tag is
not in that set, use the CPU stack; CPU workers are fully supported. Check your
GPU:

```sh
nvidia-smi --query-gpu=compute_cap --format=csv,noheader
```

Strip the dot (`8.9` → `89`) and pass that value to `--compute-cap`. If your
GPU's compute capability has no matching image — or the NVIDIA stack is not
working on the host — run the CPU stack instead. CPU workers are fully
supported and need none of the NVIDIA prerequisites.

## Identity and backups

On first start the worker generates a **libp2p identity** and stores it in the
worker data volume (`worker-data` by default, alongside the model cache and
receipts). This identity determines your worker's **PeerId**.

- **Losing the data volume changes your PeerId.** The network still works —
  you will simply appear as a new worker — but anything keyed to the old
  PeerId is left behind.
- **Back it up.** Either set `WORKER_DATA` in `.env` to an absolute host path
  (bind mount), which makes backup a plain `tar` of that directory, or export
  the named volume while the stack is stopped:

  ```sh
  docker compose stop node
  docker run --rm \
    -v autarcho-worker_worker-data:/data \
    -v "$PWD":/backup \
    alpine tar czf /backup/worker-data-backup.tgz -C /data .
  docker compose start node
  ```

  If you renamed the compose project, find the volume name with
  `docker volume ls` and adjust the first `-v` argument.
- Keep the backup private: the volume holds your identity key.

## Payouts

- Work is paid in **USDC on Solana mainnet**, to the address you set as
  `WORKER_SOLANA_WALLET` (the installer's `--wallet` flag).
- The gateway **verifies receipts** for completed work; the payout service
  batches verified receipts and settles them on-chain.
- The current split is **80% to the worker / 20% to the treasury**.
- A wallet's first payout creates its USDC token account on-chain. New token
  accounts may be subject to a **minimum payout threshold (currently 2 USDC)**:
  earnings below the threshold are deferred and carried into the next payout
  batch rather than lost.
- Payouts depend on verified work and network configuration. We do not
  guarantee a particular amount of work or earnings, and there is no fixed
  payout schedule.
- You are responsible for your own wallet security, keys, taxes, and legal
  obligations in your jurisdiction. The worker software never sees your
  private key — only the public address.

## Operations and security

- **Never run `latest`.** Keep `TAG=0.1.0` pinned in `.env`. GPU workers keep
  the same `TAG` and set `WORKER_CUDA_COMPUTE_CAP=75|80|86|89|90`; the GPU
  override appends `-cuda<cap>` to select the image. A moving tag means
  unreviewed code and breaks rollback.
- **Update deliberately:**

  ```sh
  docker compose pull
  docker compose up -d
  ```

  On GPU workers, use the layered `-f docker-compose.yml -f
  docker-compose.gpu.yml` form. Read the release notes for the new version
  before updating, and keep your `.env` on the new pinned tag.
- **No inbound ports.** The compose file publishes none, by design. Do not add
  `ports:` mappings; the worker is reachable because it dials the gateway, not
  because anyone can dial it.
- **Follow the EULA.** See [EULA.md](EULA.md) for the licence, acceptable-use,
  sanctions, and prompt-handling terms. The installer records the accepted
  version in `.env`.
- **Logs:**

  ```sh
  docker compose logs -f node
  ```

## Troubleshooting

**Bootstrap fetch fails** (`install.sh` errors, or the node logs a bootstrap
/receipt URL failure):

```sh
curl -fsS https://api.autarcho.com/bootstrap.json
```

If that fails from the host, the problem is upstream of the worker: check DNS
resolution of `api.autarcho.com`, your outbound 443 access, and any corporate
proxy or TLS-intercepting firewall.

**DNS / dial-address problems:** the gateway publishes a dialable multiaddr in
`bootstrap.json` (currently `/dns4/api.autarcho.com/tcp/4001/p2p/<PeerId>`).
The installer copies that address, including the `/p2p/<PeerId>` suffix, into
`GATEWAY_P2P_ADDR`; do not strip the suffix or point it at a different host.
If DNS resolution or outbound TCP 4001 is blocked, the worker will fetch the
bootstrap document over HTTPS but never connect to the gateway.

**Connected to HTTPS but never receives jobs:** the worker needs outbound TCP
**4001** to the gateway's public IP. Test reachability from the host:

```sh
timeout 5 bash -c '</dev/tcp/<GATEWAY_IP>/4001' && echo ok
```

If that times out, allow outbound TCP 4001 (and outbound UDP if your
environment also filters datagrams) in the host or upstream firewall.

**Container dies with OOM, or inference fails under load:** the baseline is
16 GB RAM. Inspect usage with `docker stats`. If you lowered limits, keep
`WORKER_MAX_MEMORY_BYTES` at roughly 75% or less of `WORKER_MEM_LIMIT`; a
capacity value larger than the container limit will cause out-of-memory
kills. Also confirm you have 20+ GB free disk for the model cache.

**GPU not visible in the container:** confirm `nvidia-smi` works on the host,
the NVIDIA container toolkit is installed and configured for Docker (restart
Docker after configuring), and you started with both compose files layered:
`docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d`.

**CUDA errors or crashes on start after picking a GPU capability:** re-check
the compute capability and `WORKER_CUDA_COMPUTE_CAP` in `.env`:

```sh
nvidia-smi --query-gpu=compute_cap --format=csv,noheader
```

`8.9` means `WORKER_CUDA_COMPUTE_CAP=89` (with `TAG=0.1.0`). Mismatched
driver/CUDA combinations fail at startup; the safe fallback is the CPU stack
(`TAG=0.1.0`, plain `docker compose up -d`).

## Uninstall

```sh
docker compose down
```

Add `-v` only if you also want to delete the data volume — that destroys your
worker identity and cached models permanently.
