CLI & Developer Guide
1. Binaries
| Binary | Package | Default port | Purpose |
|---|---|---|---|
flatland3 |
tools/flatland |
— | Account / agent CLI (auth, character, inventory --json) — not the play client |
flatland3-gfx |
tools/flatland-gfx |
— | Only maintained play client — Macroquad + egui (make dev-play-gfx) |
flatland-gateway |
tools/gateway |
TCP 7373 |
Player TCP front door → worker wire |
flatland-worker |
tools/worker |
Wire 7391 |
Region sim (30 Hz) for one shard |
flatland-control-plane |
tools/control-plane |
HTTP 7380 |
Accounts, sessions, API tokens |
flatland-server |
tools/server |
TCP 7373 |
Legacy combined launcher (prefer gateway+worker) |
flatland-admin |
tools/flatland-admin |
— | World content admin + schema discovery |
flatland-bot |
tools/bot-harness |
— | Headless load / movement harness |
flatland-dev |
tools/flatland-dev |
— | Retired — was embedded TUI play; use gfx + dev gateway |
Build from repo root:
cargo build --workspace
2. Environment variables
| Variable | Used by | Default | Purpose |
|---|---|---|---|
DATABASE_URL |
control-plane | — | Postgres connection string |
REDIS_URL |
control-plane | — | Redis (sessions, login rate limit) |
FLATLAND_HTTP_ADDR |
control-plane | 127.0.0.1:7380 |
HTTP listen address |
FLATLAND_API_URL |
flatland auth |
http://127.0.0.1:7380 |
Control plane base URL |
FLATLAND_CONTROL_PLANE_URL |
gateway, worker | — | Control plane for game auth / mint |
FLATLAND_WORKER_ADDR |
gateway | — | Worker wire address (127.0.0.1:7391) |
FLATLAND_WORKER_LISTEN |
worker | 127.0.0.1:7391 |
Worker wire bind |
FLATLAND_GATEWAY_LISTEN |
gateway | 127.0.0.1:7373 |
Player TCP bind |
FLATLAND_REGION_ID |
worker | r1 |
Region routing key |
FLATLAND_ALLOW_DEV_LOCAL |
gateway | 1 |
Allow DevLocal Hello without account |
FLATLAND_STARTER_SEGMENT |
control-plane | repo default | Spawn point for new characters |
RUST_LOG |
all | varies | tracing filter (info, debug, …) |
Session file (after flatland auth login):
~/.config/flatland/session.json
{
"api_base": "http://127.0.0.1:7380",
"session_token": "flat_sess_…"
}
3. Local stack quickstart
cp .env.example .env
make db-up
cargo run -p flatland-control-plane-bin # terminal 1 — HTTP :7380
cargo run -p flatland-gateway # terminal 2 — game TCP :7373
cargo run -p flatland-worker # terminal 3 — region sim
make dev-play-gfx NAME=YourCharacter # terminal 4 — play (gfx)
Health check:
curl -s http://127.0.0.1:7380/v1/health | jq
4. flatland CLI
4.1 Capabilities overview
| Mode | Command | Status |
|---|---|---|
| Play | flatland3-gfx / make dev-play-gfx |
✅ Only maintained play client |
| Character | flatland3 character create/list |
✅ Explicit create; names unique per account |
flatland3 (default) |
Retired — no new work | |
flatland-dev --bots N |
Retired — use make dev-restart + make dev-play-gfx |
|
| Auth register | flatland3 auth register |
✅ Create account + auto-login |
| Auth login | flatland3 auth login |
✅ Email/password → session file |
| API tokens | flatland3 auth token create/list/revoke |
✅ Agent automation tokens |
| Capabilities | flatland3 capabilities |
✅ Print this reference in terminal |
| JSON output | flatland3 --json |
✅ Subcommands that support it |
Run flatland3 --help, flatland3 auth --help, or flatland3 capabilities for built-in help.
4.2 Auth → character → play
flatland3 auth login --email you@example.com --password '…'
flatland3 character create MadSin # once; session auth only
flatland3 character list
make dev-play-gfx NAME=MadSin # play (gfx client)
Names: 1–32 chars; start with a letter; only A–Z, 0–9, _, -. No spaces or :.
Play uses flatland3-gfx — not the flatland3 default command (TUI play retired).
4.3 Play
# Dev stack (recommended)
make dev-restart
make dev-control-plane # terminal 1
make dev-worker # terminal 2
make dev-gateway # terminal 3
make dev-play-gfx NAME=MadSin
# Or run gfx directly against gateway
flatland3-gfx --name MadSin --server 127.0.0.1:7373
Controls: WASD move, f use world, 1–9 hotbar, c dodge, q block, Space stop, Ctrl+Q quit. In-game ? for keybinds.
4.3 Auth
# Register (logs in automatically; use --no-login to skip)
flatland auth register --email you@example.com --password 'your-password' --name You
# Login only (saves session to ~/.config/flatland/session.json)
flatland auth login --email you@example.com --password 'your-password'
# Override control plane URL
flatland auth login --email you@example.com --password '…' --api http://127.0.0.1:7380
4.4 API tokens (agents / CI / LLM)
Requires login session. Token plaintext is shown once at creation.
flatland auth token create --name "ci-bot" --scope play,read
flatland auth token create --name "read-only" --scope read
flatland auth token list
flatland auth token revoke <token-uuid>
Scopes (v1):
| Scope | HTTP | Game (planned) |
|---|---|---|
read |
GET /v1/me, character reads |
— |
write |
Account mutations (future) | — |
play |
— | Connect game TCP with token |
write |
PUT/DELETE /v1/admin/* |
World content mutations |
Prefixes: flat_live_ (production), flat_test_ (with --test on create).
Agent env convention:
export FLATLAND_API_TOKEN=flat_live_…
export FLATLAND_API_URL=http://127.0.0.1:7380
5. Control plane HTTP API (v1 shipped)
Base: http://127.0.0.1:7380/v1
All responses use the agent envelope:
{ "ok": true, "data": { }, "error": null }
Errors: { "ok": false, "data": null, "error": { "code", "message", "details" } }
5.1 Health
| Method | Path | Auth |
|---|---|---|
| GET | /health, /v1/health |
none |
Returns database and redis status.
5.2 Auth & account (shipped)
| Method | Path | Auth | Body / notes |
|---|---|---|---|
| POST | /v1/auth/register |
none | { email, password, display_name } |
| POST | /v1/auth/login |
none | { email, password } → session_token |
| POST | /v1/auth/logout |
session | Authorization: Bearer flat_sess_… |
| GET | /v1/me |
session or token (read) |
Account profile |
Password rules: argon2id hash; minimum 8 characters.
Sessions: Redis, 24 h TTL, sliding on use. Prefix flat_sess_.
Login rate limit: 5 failures / 15 min per email+IP; 20 / IP.
5.3 API tokens (shipped)
| Method | Path | Auth | Body / notes |
|---|---|---|---|
| POST | /v1/me/tokens |
session only | { label, scopes[], expires_at?, test? } → token once |
| GET | /v1/me/tokens |
session only | List metadata (prefix, label, scopes) |
| DELETE | /v1/me/tokens/{id} |
session only | Revoke |
5.4 Characters & game (shipped)
| Method | Path | Auth |
|---|---|---|
| GET | /v1/characters |
session / token read |
| POST | /v1/characters |
session |
| POST | /v1/game/validate-connect |
body { auth, character_id? } (game server) |
| POST | /v1/game/checkpoint |
body { auth, character_id, position_* } |
5.5 World admin (shipped)
| Method | Path | Auth |
|---|---|---|
| GET | /v1/admin/segments |
session / token read |
| GET/PUT/DELETE | /v1/admin/segments/{id} |
read / write |
| GET/PUT/DELETE | /v1/admin/item-templates/{id} |
read / write |
| GET/PUT/DELETE | /v1/admin/building-schematics/{id} |
read / write |
| GET/POST | /v1/admin/world-objects |
read / write |
| GET/PATCH/DELETE | /v1/admin/world-objects/{id} |
read / write |
See 21 world content schemas and flatland-admin capabilities.
5.6 curl examples
# Register
curl -s -X POST http://127.0.0.1:7380/v1/auth/register \
-H 'content-type: application/json' \
-d '{"email":"you@example.com","password":"hunter2isok","display_name":"You"}' | jq
# Login
TOKEN=$(curl -s -X POST http://127.0.0.1:7380/v1/auth/login \
-H 'content-type: application/json' \
-d '{"email":"you@example.com","password":"hunter2isok"}' | jq -r '.data.session_token')
# Me (session)
curl -s http://127.0.0.1:7380/v1/me -H "Authorization: Bearer $TOKEN" | jq
# Create API token
API=$(curl -s -X POST http://127.0.0.1:7380/v1/me/tokens \
-H "Authorization: Bearer $TOKEN" \
-H 'content-type: application/json' \
-d '{"label":"ci-bot","scopes":["play","read"]}' | jq -r '.data.token')
# Me (API token with read scope)
curl -s http://127.0.0.1:7380/v1/me -H "Authorization: Bearer $API" | jq
6. Game server (flatland-server)
TCP postcard protocol on :7373. Authenticated play validates Hello via control plane when FLATLAND_CONTROL_PLANE_URL is set.
export FLATLAND_CONTROL_PLANE_URL=http://127.0.0.1:7380
cargo run -p flatland-server
flatland auth login --email you@example.com --password '…'
cargo run -p flatland
Solo dev without accounts: flatland --local.
7. flatland-admin CLI
Agent-friendly world content management. All subcommands support --json.
flatland-admin capabilities
flatland-admin schema list
flatland-admin schema show segment
flatland-admin segment validate assets/world/segments/starter-plains.yaml
flatland-admin segment upsert --file assets/world/segments/starter-plains.yaml
Auth: FLATLAND_API_TOKEN (write scope), session file from flatland auth login, or FLATLAND_SESSION_TOKEN.
8. Postgres deployment
| Environment | Approach |
|---|---|
| Local | docker compose up -d (see repo docker-compose.yml) |
| Hosted | Neon, Supabase, Railway — set DATABASE_URL only |
| CI tests | DATABASE_URL + REDIS_URL service containers |
Migrations live in migrations/; applied automatically on control-plane startup.
9. Makefile targets
make db-up # start Postgres + Redis
make db-down # stop containers
make db-logs # follow container logs
make control-plane # run flatland-control-plane
make build # cargo build --workspace
make test # cargo test --workspace
Update this doc when new CLI subcommands or HTTP routes ship.