runtime/httpapi exposes the runtime interaction protocol over JSON and
Server-Sent Events. It does not expose bot implementations directly.
- JSON requests reject unknown fields and multiple JSON values.
- Runtime protocol errors include a stable
code. - SSE event IDs are monotonic cursors. Clients reconnect with
afterorLast-Event-ID. replay=1replays retained history before live events.WithBearerAuthprotects every endpoint except/health.- Optional management endpoints return
501 Not Implementedwhen their capability is absent./capabilitiesis the authoritative discovery response.
The daemon can configure and start IM connectors without a TUI or an HTTP management client. Select one or more transports with a comma-separated service variable:
NEKOCODE_CONNECTORS=feishu,telegram
Provide credentials for the selected transports on first boot:
NEKOCODE_FEISHU_APP_ID=cli_xxx
NEKOCODE_FEISHU_APP_SECRET=xxx
NEKOCODE_TELEGRAM_BOT_TOKEN=123456:xxx
NEKOCODE_QQBOT_APP_ID=xxx
NEKOCODE_QQBOT_APP_SECRET=xxx
NEKOCODE_QQBOT_SANDBOX=false
If NEKOCODE_CONNECTORS is omitted, transports are inferred from credential
variables for backward-compatible first boot. Setting it explicitly is
recommended because it also starts connectors from persisted configuration
when credentials are no longer present in the environment. Use none to
disable all connector bootstrap.
For Feishu and Telegram, the first boot logs a short-lived pairing code or
link. Complete that action in a direct message to the bot. Pairing and
credentials are persisted in ~/.nekocode/connect.json; later daemon restarts
restore the selected connections. Keep the service user's HOME stable across
restarts. Changing the Feishu app ID clears the old owner binding and starts a
new pairing flow.
NEKOCODE_DAEMON_TOKEN is independent of connector credentials. It protects
the daemon's HTTP management API and is not needed by IM connectors.
| Method | Path | Description |
|---|---|---|
| GET | /health |
Process health and protocol version |
| GET | /status |
Runtime lifecycle and active run |
| GET | /capabilities |
Optional capability manifest |
| POST | /input |
Start a run |
| GET | /events?run_id=&after=&replay=1 |
Subscribe to runtime events |
| GET | /runs?limit=50 |
List recent run snapshots |
| GET | /runs/current |
Read the latest run snapshot |
| GET | /runs/{runID} |
Read one run snapshot |
| POST | /runs/{runID}/abort |
Cancel the active run |
| POST | /approvals/{approvalID} |
Resolve a pending approval |
| POST | /questions/{questionID} |
Answer or reject a pending question |
| GET | /connect |
Read connector state |
| POST | /connect/{name} |
Configure or start a connector |
| POST | /disconnect/{name} |
Stop a connector |
| GET | /model |
Read the active provider and model |
| GET | /commands |
Compatibility list derived from the / and $ root menus |
| GET | /commands/menu?input=/model |
Resolve a transport-neutral command menu |
| GET | /metrics |
Read the latest operational metrics |
| GET | /context |
Read the context snapshot |
| GET | /memory?scope=project |
Read project memory |
| GET | /sessions |
List sessions |
| GET | /sessions/current/messages |
Read current session messages |
POST /input accepts:
{
"text": "hello",
"source": {"kind": "http", "id": "client-1"},
"sender": {"id": "user-1"}
}The response is 202 Accepted with {"run_id":"run_1"}. A blank
source.kind defaults to http.
Approval:
{"allowed":true,"remember":false,"allow_with_permission":false}Question:
{"answers":[["choice-a"]],"rejected":false}Connector commands accept an optional body:
{"args":["status"]}Each SSE item contains the stable event type and the complete versioned event:
id: evt_12
event: run_done
data: {"version":"2.0","id":"evt_12","sequence":12,"run_id":"run_1","type":"run_done","payload":{"output":"done"}}
The main lifecycle events are run_started, run_done, run_failed, and
run_aborted. Streaming, tool, approval, question, session, connector, and
metrics changes use their corresponding typed runtime events.