# Local Gateway Control — Per-Platform Commands

Copy-pasteable stop/start/verify commands for the local gateway on each platform. The user runs these from a regular terminal, **not** from inside a Hermes session — the CLI blocks `gateway stop`/`restart`/`run` from inside a running gateway on purpose (SIGTERM would kill the command itself).

## Detect the platform first

```bash
uname -s
```

Returns `Linux`, `Darwin`, or `MINGW64_NT-*` / `CYGWIN_NT-*` for Windows shells. If you can't run shell commands, look at the prompt and the user's existing output:

- `PS C:\>`, `PS C:\Users\...>` → Windows PowerShell
- `>` (no `PS`) with backslashes in paths → cmd.exe
- `$ ` alone with forward slashes → POSIX shell (bash/zsh)

## Linux — bash / zsh

### Inventory (run first)

```bash
ps -ef | grep -iE "hermes|gateway" | grep -v grep
ss -tlnp 2>/dev/null | grep -E "9119|hermes" || netstat -tlnp 2>/dev/null | grep -E "9119|hermes"
cat ~/.hermes/gateway_state.json 2>/dev/null
systemctl --user status hermes-gateway 2>/dev/null
ls /etc/systemd/system/ | grep -i hermes
crontab -l 2>/dev/null | grep -i hermes
```

### Stop everything

```bash
hermes gateway stop
sudo systemctl disable --now hermes-gateway.service
pkill -f 'hermes serve --port 9119'
```

> ⚠️ The `pkill -f 'hermes serve --port 9119'` line above is **wrong** for one specific case: when the `hermes serve` on 9119 is the TUI session's own local chat backend. Detect that case by checking the process's children:
>
> ```bash
> ps -ef | grep -E "hermes serve" | grep -v grep
> # If the PPID is 1 AND any child has --session-key <sid>, this is the TUI backend. Do NOT kill it.
> ```
>
> In that case, omit the `pkill` line. The TUI backend will exit naturally when the TUI session ends, and killing it ends the active chat.

### Verify it's all gone

```bash
sleep 2
ps -ef | grep -i hermes | grep -v grep
ss -tlnp 2>/dev/null | grep 9119
systemctl --user status hermes-gateway 2>/dev/null
```

All three should return empty (with the caveat above about the TUI backend).

### If the gateway keeps respawning — the user-systemd layer

Systemd's `Restart=always` will keep the gateway alive even after a clean stop, especially if the Web UI's Stop button was used. Disable the unit, then also check the user-level systemd that `hermes gateway run` itself forks:

```bash
# System unit
sudo systemctl disable --now hermes-gateway.service
systemctl is-enabled hermes-gateway.service   # expect: disabled

# User unit (if it exists)
find /root /etc/systemd/user -name "hermes-gateway*" 2>/dev/null
systemctl --user disable --now hermes-gateway.service 2>&1
# If "Unit file ... does not exist": user systemd is supervising via a transient in-memory unit, nothing to disable — kill the process group instead

# Manual kill of the gateway process group (if still alive)
ps -ef | grep "hermes.*gateway" | grep -v grep
# Kill the parent PID first (often a bash launcher), then the child python process
kill -9 <parent_pid> <child_pid>

# Receipt: the restart counter should stop climbing
journalctl -u hermes-gateway.service --since "5 min ago" | grep "restart counter" | tail -3
```

### Clean start (single gateway)

```bash
# Pick ONE of these — never both.
hermes gateway run                    # foreground (tmux/nohup if you want it persistent)
sudo systemctl enable --now hermes-gateway.service   # supervised (recommended for servers)
```

## macOS — zsh

The same `hermes` commands work, but there's no systemd. Use `launchctl` if you installed the service via `hermes gateway install`.

```bash
hermes gateway stop
launchctl list | grep -i hermes        # see if a launchd job is registered
# If yes:
launchctl unload ~/Library/LaunchAgents/<hermes-job>.plist
lsof -i :9119                          # see what's holding 9119
kill <PID>                             # or: pkill -f 'hermes serve --port 9119'
```

## Windows — PowerShell

### Inventory (run first)

```powershell
Get-Process | Where-Object { $_.Name -like "*hermes*" } | Select-Object Id, Name, StartTime, CommandLine | Format-List
Get-Service    | Where-Object { $_.Name -like "*hermes*" }
```

### Stop everything

```powershell
hermes gateway stop
# Get-Service should now show Stopped. If it does not, the service may be missing
# or the install never used the service mechanism.
Get-Process | Where-Object { $_.Name -like "*hermes*" } | Select-Object Id, Name, StartTime, CommandLine
# Inspect CommandLine for each process. If they all show gateway/serve (NOT the
# Desktop app), kill them all:
Get-Process | Where-Object { $_.Name -like "*hermes*" } | Stop-Process -Force
```

### Safety check before killing on Windows

`Stop-Process -Force` on a `Hermes`-named process can take down the Hermes Desktop app the user is using for their UI. Always:

1. List the processes with `CommandLine` visible.
2. Confirm every entry's `CommandLine` looks like a gateway / serve / worker (paths under `\.hermes\venv\...`, arguments like `gateway run` or `serve --port 9119` or `tui_gateway.slash_worker`).
3. If any `CommandLine` points at the Desktop app's installed binary (under `Program Files\...` or in the user's start-menu app), **stop and ask the user** which PIDs to kill.

### Verify it's all gone

```powershell
Get-Process | Where-Object { $_.Name -like "*hermes*" }   # expect: empty
Get-Service    | Where-Object { $_.Name -like "*hermes*" } # expect: empty or "Stopped"
```

### Clean start (single gateway)

```powershell
hermes gateway start     # if installed as a Windows service
# OR
hermes gateway run       # foreground in this terminal
```

## After the stop — verify the surviving side is the only one

This is independent of platform. From anywhere with network access to the gateway that *should* still be running:

```bash
curl -ksS -m 5 -o /dev/null -w "HTTP %{http_code} | %{time_total}s\n" https://<gateway-host>/
curl -ksS -m 5 https://<gateway-host>/openapi.json | python3 -c "import json,sys; d=json.load(sys.stdin); print('title:', d['info']['title'], '| version:', d['info']['version'])"
```

Expect HTTP 200, title `Hermes Agent`. If you get a different title or a connection error, the wrong gateway was stopped.

## Common mistakes

- **`sudo systemctl disable --now hermes-gateway.service` on a system without systemd** — fails. On Windows / macOS without launchd, skip it. The `hermes gateway stop` and the process kill are the substantive parts.
- **`pkill -f 'hermes serve --port 9119'` on Windows** — `pkill` doesn't exist in PowerShell. Use `Get-Process ... | Stop-Process -Force` instead.
- **Running the stop from inside a Hermes TUI/gateway session** — CLI blocks it. Tell the user to open a separate terminal.
- **Forgetting to `systemctl disable`** — the next boot respawns the gateway and you're back where you started.
