Runtime API Design
The rationale and design decisions behind Alice's local HTTP API.
Why a Local API?
Alice runs bundled skills as subprocess scripts. These scripts need to interact with the running connector — send images, manage tasks, query state. Direct Go interop isn't possible from shell scripts, so Alice exposes a local HTTP API.
Design Principles
1. Local-Only by Default
The API binds to 127.0.0.1 (configurable via runtime_http_addr). It is not designed to be exposed to the network. If you need remote access, use a reverse proxy or SSH tunnel — but this is not the intended use case.
2. Bearer Token Auth
Every request (except /healthz) requires:
Authorization: Bearer <token>
The token is auto-generated at startup. Environment variables (ALICE_RUNTIME_API_TOKEN) inject it into skill scripts automatically.
3. Defense in Depth
Multiple layers of protection:
- Auth rate limiting: 120 requests per minute per token
- Body size limit: 1 MB per request
- File validation: Uploaded files must be readable, non-empty regular files
- Feishu size limits: Uploads are still subject to Feishu's file size and type restrictions
4. No Text Send Endpoint
The runtime API does not have a plain text send endpoint. Why?
Text replies normally go through the main reply pipeline — they need session context, proper threading, and reply metadata. The runtime API is designed for side-effects (sending images, files, managing tasks), not for bypassing the reply pipeline.
If a skill needs to send a text message as an automation task, it creates a send_text task via the automation API. The automation engine handles the rest.
API Surface
Messages
POST /api/v1/messages/image— upload and send an imagePOST /api/v1/messages/file— upload and send a file
Both accept multipart/form-data with an optional caption field.
Automation
- Full CRUD for automation tasks: create, list, get, update, delete
Goal
- Goal lifecycle management: get, create, pause, resume, complete, delete
Health
GET /healthz— no auth, responds 200 if the server is running
Environment Variable Injection
Skills don't need to know the API address or token. Alice injects them:
ALICE_RUNTIME_API_BASE_URL="http://127.0.0.1:7331"
ALICE_RUNTIME_API_TOKEN="<auto-generated>"
ALICE_RUNTIME_BIN="/usr/local/bin/alice"
Additional context variables:
ALICE_RECEIVE_ID_TYPE="chat_id"
ALICE_RECEIVE_ID="oc_xxxxxxxxxxxxx"
ALICE_SOURCE_MESSAGE_ID="om_xxxxxxxxxxxxx"
ALICE_ACTOR_USER_ID="ou_xxxxxxxxxxxxx"
ALICE_ACTOR_OPEN_ID="ou_xxxxxxxxxxxxx"
ALICE_CHAT_TYPE="group"
ALICE_SESSION_KEY="chat_id:oc_xxx|scene:chat"
Multi-Bot API Ports
In multi-bot mode, each bot gets its own Runtime API server on an auto-incremented port:
| Bot Index | Port |
|---|---|
| First | 7331 |
| Second | 7332 |
| Third | 7333 |
| ... | ... |
Skills target the correct bot by inheriting environment variables from the conversation scope they're triggered in.
Graceful Shutdown
When Alice receives a shutdown signal, the Runtime API server:
- Stops accepting new connections
- Waits up to
runtime_api_shutdown_timeout_secs(default: 5s) for in-flight requests to complete - Force-closes remaining connections after timeout
Extending the API
New endpoints can be added in internal/runtimeapi/. See the Contributing guide and Architecture Overview for developer guidance.