Local Server and API
Jarvis Code CLI ships with a built-in API-only local server. Running jarvis server starts a foreground process that exposes a REST API (/api/v1) and a WebSocket event stream (/api/v1/ws) for scripts and third-party tools.
Make sure Jarvis Code CLI is installed and ready to use first — either logged in via
/login(in the TUI, or withjarvis login), or with a provider configured inconfig.toml. The server shares the CLI's login state and configuration, so no separate credential is needed for it.
WARNING
The REST and WebSocket APIs described on this page are experimental: interface stability is not guaranteed, and endpoints, fields, and event types may change in any release. When integrating, rely on the /openapi.json and /asyncapi.json documents served by your version.
Start the server
jarvis server
jarvis server --port 58628
jarvis server --host 127.0.0.1The server binds to 127.0.0.1:58627 by default (loopback only). If the port is taken it automatically retries with the next one, so multiple instances can coexist on the same machine; each instance registers under ~/.jarvis-code/server/instances/. The startup banner prints the access URL and the plaintext token:
Jarvis server ready
API: http://127.0.0.1:58627
Token: ...
Logs: off use --log-level info to enable
Stop: Ctrl+CThe server runs in the foreground; press Ctrl-C for a clean shutdown. For the full option list such as --host and --log-level, see the jarvis command reference.
Authentication
Every /api/* endpoint requires a bearer token (any request carrying this string is treated as authorized). The token is generated on the first server boot, persisted at ~/.jarvis-code/server.token (file mode 0600), and reused across restarts.
Pick the carrying method that fits your client:
- REST: the
Authorization: Bearer <token>request header. - WebSocket: clients that can set headers use
Authorization: Bearer; clients that cannot (such as browsers) pass the subprotocol (a protocol name declared during the WebSocket handshake)jarvis-code.bearer.<token>instead.
If the token leaks, run jarvis server rotate-token: the new token is written to server.token immediately, the old one stops working at once, and running instances pick up the new token without a restart.
When binding to a non-loopback address (--host), set JARVIS_CODE_PASSWORD as an additional credential. The persistent bearer token remains valid; the password does not replace it. The server rate-limits authentication failures on non-loopback binds.
DANGER
--dangerous-bypass-auth disables authentication entirely — anyone who can reach the port can control your sessions, file system, and shell. Only use it on trusted networks or behind your own authenticating proxy. See the jarvis command reference.
Drive a session over the API
The minimal flow with curl: check the server → create a session → subscribe to events → submit a prompt → read history back. The examples assume the server runs at the default address and the token is stored in the shell variable TOKEN.
- Check server status:
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:58627/api/v1/metaEvery JSON response is wrapped in a uniform envelope — { "code": 0, "msg": "success", "data": ..., "request_id": "..." }. The business outcome lives in code (0 means success); the HTTP status only reports transport-level results.
- Create a session;
metadata.cwdsets the working directory:
curl -s -X POST http://127.0.0.1:58627/api/v1/sessions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"metadata": {"cwd": "/path/to/project"}}'The returned data.id (shaped like session_...) is the session id used by every subsequent request.
- Connect to the WebSocket and subscribe to session events. Any WebSocket client works; below is a dependency-free Node.js script (Node.js 22+ ships a built-in
WebSocketclient):
// subscribe.mjs — usage: TOKEN=... node subscribe.mjs session_...
const ws = new WebSocket('ws://127.0.0.1:58627/api/v1/ws', [
`jarvis-code.bearer.${process.env.TOKEN}`,
]);
ws.onmessage = (e) => console.log(e.data);
ws.onopen = () =>
ws.send(
JSON.stringify({
type: 'subscribe',
id: '1',
payload: { session_ids: [process.argv[2]] },
}),
);- Submit a prompt:
curl -s -X POST http://127.0.0.1:58627/api/v1/sessions/<session_id>/prompts \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"content": [{"type": "text", "text": "Introduce this repository in one sentence"}]}'The subscriber sees, in order: turn.started (turn begins) → assistant.delta (streaming text increments) → tool.call.started / tool.result when tool calls happen → turn.ended (turn finishes).
- Read history back over REST at any time:
curl -s -H "Authorization: Bearer $TOKEN" \
"http://127.0.0.1:58627/api/v1/sessions/<session_id>/messages?page_size=20"Live specification documents
While running, the server describes itself with two specification documents, both requiring the bearer token:
GET /openapi.json— an OpenAPI document for the REST API, with request/response schemas for every endpoint; import it into Swagger UI, Postman, and similar tools.GET /asyncapi.json— an AsyncAPI document for the WebSocket protocol, covering control frames and event types.
Next steps
- Server API — full REST endpoint inventory, error codes, WebSocket events, and the transcript protocol
- jarvis command — all
jarvis servercommand-line options