InitRunner

API Server

The initrunner serve command exposes any agent as an OpenAI-compatible HTTP API. Use InitRunner agents as drop-in replacements for OpenAI in any client that speaks the chat completions format — including the official OpenAI SDKs, curl, and tools like Open WebUI.

Quick Start

# Start the server
initrunner serve role.yaml

# With authentication
initrunner serve role.yaml --api-key my-secret-key

# Custom host/port
initrunner serve role.yaml --host 0.0.0.0 --port 3000

CLI Options

OptionTypeDefaultDescription
role_filePath(required)Path to the role YAML file
--hoststr127.0.0.1Host to bind to (0.0.0.0 for all interfaces)
--portint8000Port to listen on
--api-keystrnullAPI key for Bearer token authentication
--audit-dbPath~/.initrunner/audit.dbAudit database path
--no-auditboolfalseDisable audit logging

Endpoints

GET /health

Always returns 200 OK. Not protected by authentication.

{"status": "ok"}

GET /v1/models

Lists available models. Returns the agent's metadata.name as the model ID.

{
  "object": "list",
  "data": [
    {
      "id": "my-agent",
      "object": "model",
      "created": 1700000000,
      "owned_by": "initrunner"
    }
  ]
}

POST /v1/chat/completions

The main chat completions endpoint. Accepts the standard OpenAI request format.

FieldTypeDefaultDescription
modelstr""Model name (ignored — uses role config)
messageslist[]Conversation messages (role + content)
streamboolfalseEnable SSE streaming

Streaming

When stream: true, the server responds with Server-Sent Events (SSE):

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"delta":{"role":"assistant"}}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"delta":{"content":"Hello"}}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"delta":{},"finish_reason":"stop"}]}

data: [DONE]

Multi-Turn Conversations

Use the X-Conversation-Id header for server-side conversation history:

  1. Send a request with X-Conversation-Id: conv-001.
  2. The server stores message history after each request.
  3. Subsequent requests with the same ID use stored history — only the last user message is the new prompt.
  4. Conversations expire after 1 hour of inactivity.

Authentication

When --api-key is set, all /v1/* endpoints require:

Authorization: Bearer <api-key>

The /health endpoint is never protected.

Usage Examples

curl

curl http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

curl (with auth and conversation)

# First message
curl http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer my-secret-key" \
  -H "X-Conversation-Id: conv-001" \
  -d '{"messages": [{"role": "user", "content": "My name is Alice."}]}'

# Follow-up
curl http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer my-secret-key" \
  -H "X-Conversation-Id: conv-001" \
  -d '{"messages": [{"role": "user", "content": "What is my name?"}]}'

OpenAI Python SDK

from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:8000/v1",
    api_key="my-secret-key",  # or "unused" if no --api-key set
)

response = client.chat.completions.create(
    model="my-agent",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)

OpenAI Python SDK (streaming)

from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:8000/v1",
    api_key="unused",
)

stream = client.chat.completions.create(
    model="my-agent",
    messages=[{"role": "user", "content": "Tell me a story."}],
    stream=True,
)
for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")

OpenAI Node.js SDK

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "http://127.0.0.1:8000/v1",
  apiKey: "my-secret-key",
});

const response = await client.chat.completions.create({
  model: "my-agent",
  messages: [{ role: "user", content: "Hello!" }],
});
console.log(response.choices[0].message.content);

On this page