Skip to main content

Headless mode (--no-gui)

Skip the desktop window entirely and run Seraph as a pure HTTP API host. Every backend service stays alive — license heartbeat, bot manager, slot sweeper, REST + SSE bridge — but no Tauri webview opens.

seraph.exe --no-gui
# or, equivalent
seraph.exe --headless

The startup banner switches:

[seraph] api on http://0.0.0.0:8090 (PIN=798465 at C:\Users\<you>\AppData\Roaming\Seraph\pin.txt)
[seraph] headless mode (--no-gui) — UI window suppressed; HTTP API on http://0.0.0.0:8090

Logging into your Seraph account

Every bot-control command runs through require_active_license, which means the operator has to be logged in to a Seraph account with an active license before any bot will spawn or warp.

Three ways to handle the login:

1. Pass credentials at launch (preferred)

seraph.exe --no-gui \
--seraph-user yourname \
--seraph-pass yourpassword

The bin auto-logs in during startup, fetches a signed lease, and prints:

[seraph] headless auto-login as yourname…
[seraph] license active: plan=premium max_slots=100

After that, every /api/bots/... / /invoke call passes the license gate.

2. Use environment variables

Same result, with the credentials kept out of the process arg list:

SERAPH_USER=yourname SERAPH_PASS=yourpassword seraph.exe --no-gui

Useful for systemd units, Set-Item Env:SERAPH_USER in PowerShell, or .env files loaded by your launcher.

3. Login via the HTTP API after launch

For interactive operators or one-off scripts:

# 1. Boot headless.
seraph.exe --no-gui

# 2. Exchange the PIN (printed at startup) for a bearer token.
PIN=$(grep -oE '[0-9]{6}' "$APPDATA/Seraph/pin.txt")
TOKEN=$(curl -s -X POST -H 'content-type: application/json' \
-d "{\"pin\":\"$PIN\"}" http://localhost:8090/auth/pin | jq -r .token)

# 3. Login to Seraph (talks to licensing server, drops a session
# token at %LOCALAPPDATA%\seraph\auth\session_token).
curl -s -X POST http://localhost:8090/invoke \
-H "authorization: Bearer $TOKEN" \
-H "content-type: application/json" \
-d '{"cmd":"seraph_login","args":{"username":"yourname","password":"yourpassword"}}'

# 4. Now spawn / warp / disconnect bots — every command passes the
# license gate while this session stays valid.
curl -s -X POST http://localhost:8090/invoke \
-H "authorization: Bearer $TOKEN" \
-H "content-type: application/json" \
-d '{"cmd":"spawn_bot_email","args":{
"email":"[email protected]",
"password":"botpass",
"aid":null
}}'

The next launch reuses the saved session token (no re-login needed) until it expires or you seraph_logout.

When to use each path

PathBest for
--seraph-userunattended servers / docker / systemd / cron — fire-and-forget
SERAPH_USERsame as above, but credentials don't show in ps/Task Manager
/invoke seraph_logininteractive ops, scripted login from existing tooling

Auth still applies

Every endpoint behind the bearer token still gates the same way as the GUI build — pull the PIN from pin.txt after launch, exchange it for a token via POST /auth/pin, then use that bearer for everything else. See Authentication.

Discovery

Hit GET /api/commands for the full list of dispatch commands the running binary exposes — it's the canonical way to learn what's reachable in headless mode without a code-walk.

Limits

  • No login UI, no PIN entry dialog. The PIN file path is printed at startup; copy it from there.
  • The licensing dashboard tab (subscription, redeem code) doesn't exist in this mode. Use POST /invoke with cmd: "seraph_login" / seraph_redeem_key etc. directly, or pass --seraph-user / SERAPH_USER at launch.
  • The slot sweeper still runs — bots over the plan cap get reaped.
  • Without a successful Seraph login, every bot command returns {"error":"not_logged_in: sign in to your Seraph account first"}. Login first, then drive bots.