# Gateway API Server: Env Vars vs Config.yaml Trap

## Symptom

- Hermes Desktop shows "connecting" indefinitely
- `ss -tlnp | grep 18789` returns nothing
- `journalctl --user -u hermes-gateway` shows repeated:
  ```
  ERROR gateway.platforms.api_server: [Api_Server] Refusing to start:
  API_SERVER_KEY is required for the API server, including loopback-only
  binds on 127.0.0.1.
  ```
- Gateway process IS running, but the API server module never starts
- `curl http://127.0.0.1:18789/v1/models` gets connection refused

## Root Cause

Hermes v0.13.0 gateway reads `api_server` configuration **exclusively from environment variables**, NOT from the `api_server:` block in `config.yaml`.

The `api_server:` block in `config.yaml` is a separate configuration path used only by the `hermes setup` web UI wizard — the gateway's `load_gateway_config()` function in `gateway/config.py` never reads it.

The only env vars the gateway checks:

| Variable | Required | Source line | Default |
|----------|----------|-------------|---------|
| `API_SERVER_ENABLED` | yes | `config.py:1518` | empty (must be `true`) |
| `API_SERVER_KEY` | yes | `config.py:1519` | empty (gateway refuses to start) |
| `API_SERVER_PORT` | no | `config.py:1521` | 8642 |
| `API_SERVER_HOST` | no | `config.py:1522` | 127.0.0.1 |
| `API_SERVER_CORS_ORIGINS` | no | `config.py:1520` | empty |
| `API_SERVER_MODEL_NAME` | no | `config.py:1540` | profile name or "hermes-agent" |

## Source Code (v0.13.0)

### `gateway/config.py` lines 1517-1542 — where env vars are read

```python
# API Server
api_server_enabled = os.getenv("API_SERVER_ENABLED", "").lower() in {"true", "1", "yes"}
api_server_key = os.getenv("API_SERVER_KEY", "")
api_server_cors_origins = os.getenv("API_SERVER_CORS_ORIGINS", "")
api_server_port = os.getenv("API_SERVER_PORT")
api_server_host = os.getenv("API_SERVER_HOST")
if api_server_enabled or api_server_key:
    if Platform.API_SERVER not in config.platforms:
        config.platforms[Platform.API_SERVER] = PlatformConfig()
    config.platforms[Platform.API_SERVER].enabled = True
    if api_server_key:
        config.platforms[Platform.API_SERVER].extra["key"] = api_server_key
    ...
```

### `gateway/platforms/api_server.py` line 760 — where `self._api_key` is set

```python
self._api_key: str = extra.get("key", os.getenv("API_SERVER_KEY", ""))
```

### `gateway/platforms/api_server.py` lines 4307-4313 — auth guard

```python
if not self._api_key:
    logger.error(
        "[%s] Refusing to start: API_SERVER_KEY is required ..."
    )
    return False
```

### `hermes_cli/web_server.py` lines 4453-4465 — the env var spec

```python
"api_server": {
    "name": "API server",
    "env_vars": (
        "API_SERVER_ENABLED",
        "API_SERVER_KEY",
        "API_SERVER_PORT",
        "API_SERVER_HOST",
        "API_SERVER_MODEL_NAME",
    ),
    ...
}
```

## Fix

Add to `~/.hermes/.env`:

```
API_SERVER_ENABLED=true
API_SERVER_KEY=<your-key-here>
API_SERVER_PORT=18789
API_SERVER_HOST=0.0.0.0
```

Then restart the gateway:

```bash
systemctl --user restart hermes-gateway
```

(A `reset-failed` may be needed if the unit is in a failed state.)

## Verification

```bash
# 1. Is the port listening?
ss -tlnp | grep 18789
# Expected: LISTEN ... 0.0.0.0:18789 ... users:(("hermes",...))

# 2. Does the API respond?
curl -s http://127.0.0.1:18789/v1/models \
  -H "Authorization: Bearer <your-key>"
# Expected: {"object":"list","data":[{"id":"hermes-agent",...}]}

# 3. Any errors in the journal?
journalctl --user -u hermes-gateway --since "1min ago" | grep -i "api_server"
# Expected: no "Refusing to start" errors
```

## Why This Happens

The `api_server:` block in `config.yaml` was added by `hermes config set api_server.key ...` and looks authoritative. A user migrating from an earlier Hermes version (where env vars were the only mechanism) to a version with a richer config.yaml may assume the gateway reads config.yaml. It does not — for the API server specifically.

The env-vars-only design is intentional: `API_SERVER_KEY` is a secret and belongs in `.env` (the credential store), not in `config.yaml` (which may be committed or backed up). But the `api_server:` block in config.yaml is misleading because it documents the intended config without actually activating it.
