OpenForge logo
API Reference

Build on the OpenForge API

A RESTful API with first-class SSE streaming. Eight core endpoints, 16+ event types, and copy-paste examples in Python, JavaScript, curl, and Go.

Base URL
http://localhost:8000/api

All endpoints are prefixed with /api. Bearer auth via Authorization: Bearer <token> header is required unless noted.

Endpoints

Core endpoints

Click any row to copy its full URL to your clipboard.

MethodPathDescriptionAuth
GET
/api/skills
List all 40 skills with metadata, category, and tags.Required
POST
/api/skills/{name}/execute
Execute a named skill with the provided input payload.Required
GET
/api/sessions
List all persisted sessions with metadata and timestamps.Required
POST
/api/chat
Send a chat message — returns SSE stream of events.Required
GET
/api/memory
Read MEMORY.md, USER.md, and PROCEDURES.md files.Required
POST
/api/memory
Write or append to memory files (HITL-protected).Required
GET
/api/providers
List configured LLM providers with status and models.Required
GET
/api/health
Liveness + readiness probe for load balancers.Open
Quick start

Code examples

Pick your language — every example lists skills, executes one, and streams a chat response.

import requests
import json

BASE = "http://localhost:8000/api"
TOKEN = "openforge_your_bearer_token"
HEADERS = {
    "Authorization": f"Bearer {TOKEN}",
    "Content-Type": "application/json",
}

# 1. List all 40 skills
r = requests.get(f"{BASE}/skills", headers=HEADERS)
skills = r.json()
print(f"{len(skills)} skills available")

# 2. Execute a skill
r = requests.post(
    f"{BASE}/skills/code_review/execute",
    headers=HEADERS,
    json={"input": {"file": "main.py", "content": "print('hi')"}},
)
print(r.json()["output"])

# 3. Stream a chat response (SSE)
with requests.post(
    f"{BASE}/chat",
    headers={**HEADERS, "Accept": "text/event-stream"},
    json={"message": "Explain this codebase", "stream": True},
    stream=True,
) as resp:
    for line in resp.iter_lines():
        line = line.decode()
        if line.startswith("data:"):
            evt = json.loads(line[5:].strip())
            print(evt.get("delta", ""), end="", flush=True)
python
Realtime

SSE event types

The /api/chat stream emits 16+ structured Server-Sent Events. Each event has a stable type and a JSON data payload.

session.start

Emitted when a new session is created. Contains session_id and persona.

event: session.start
data: {"session_id":"sess_99","persona":"architect","ts":"2025-02-14T09:42:11Z"}
session.end

Emitted when a session is closed or expires.

event: session.end
data: {"session_id":"sess_99","reason":"user_close"}
message.start

Marks the beginning of an assistant message.

event: message.start
data: {"message_id":"msg_42","role":"assistant"}
message.delta

Streamed token / chunk of the assistant message.

event: message.delta
data: {"message_id":"msg_42","delta":"Hello"}
message.end

Marks the end of an assistant message with stats.

event: message.end
data: {"message_id":"msg_42","tokens":142,"duration_ms":1820}
think.start

Agent begins an internal reasoning step (visible in TUI).

event: think.start
data: {"step":"planning","persona":"architect"}
think.delta

Streamed reasoning token.

event: think.delta
data: {"delta":"Analyzing codebase..."}
think.end

Agent finished reasoning, about to act.

event: think.end
data: {"duration_ms":420}
tool.start

A tool is about to be invoked.

event: tool.start
data: {"tool":"file_read","args":{"path":"main.py"}}
tool.end

A tool finished, returns its result summary.

event: tool.end
data: {"tool":"file_read","ok":true,"bytes":2048}
tool.approval

HITL approval requested for a destructive tool.

event: tool.approval
data: {"tool":"terminal_exec","command":"rm -rf build","risk":"high"}
skill.invoke

An AI skill (e.g. code_review) is being executed.

event: skill.invoke
data: {"skill":"code_review","target":"main.py"}
provider.swap

Active LLM provider was changed at runtime.

event: provider.swap
data: {"from":"openai","to":"anthropic","reason":"rate_limit"}
memory.write

A memory file was updated.

event: memory.write
data: {"file":"MEMORY.md","bytes":512,"append":true}
error

Non-fatal error during streaming (agent may continue).

event: error
data: {"code":"tool_timeout","tool":"web_search","retry":true}
done

Terminal event — stream is now closed.

event: done
data: {"tokens":1240,"duration_ms":3840}
Schemas

Request & response examples

The /api/chat endpoint is the workhorse — here's exactly what goes in and what comes out.

POSTRequest body
# POST /api/chat — request body
{
  "message": "Refactor this function for readability",
  "session_id": "sess_99",                  // optional, omit to create new
  "persona": "architect",                   // optional, default: user's last
  "provider": "anthropic",                  // optional, default: configured
  "stream": true,                           // SSE stream (recommended)
  "context": {                              // optional, additional context
    "files": ["src/main.ts"],
    "selections": [{"path":"src/main.ts","start":12,"end":42}]
  },
  "tools": {                                // optional, tool overrides
    "allow": ["file_read", "file_patch"],
    "deny": ["terminal_exec"]
  },
  "memory": {                               // optional, memory overrides
    "recall": true,                         // fetch relevant memories
    "write": true                           // allow writing to MEMORY.md
  }
}
json
200 OKResponse body
# POST /api/chat — non-streaming response
{
  "session_id": "sess_99",
  "message_id": "msg_42",
  "role": "assistant",
  "content": "Here's a cleaner version of the function:\n\n...",
  "persona": "architect",
  "provider": "anthropic",
  "model": "claude-3-5-sonnet-20241022",
  "tokens": { "input": 312, "output": 184, "total": 496 },
  "duration_ms": 1820,
  "tools_used": [
    {"tool": "file_read", "ok": true, "duration_ms": 18},
    {"tool": "file_patch", "ok": true, "duration_ms": 42}
  ],
  "memory_updated": ["MEMORY.md"],
  "confidence": 0.92
}

# Error response (HTTP 4xx / 5xx)
{
  "error": {
    "code": "rate_limited",
    "message": "Provider rate limit reached. Retry in 12s.",
    "retry_after": 12,
    "request_id": "req_8f3a2b"
  }
}
json
Skills API

Execute a skill

Every skill accepts a JSON input payload and returns a structured output. See the Skills Catalog for per-skill schemas.

POSTSkill request
# POST /api/skills/{name}/execute — request
{
  "input": {
    "file": "src/auth/login.ts",
    "content": "export function login(u,p){return fetch(...)}",
    "focus": ["security", "readability"]
  },
  "session_id": "sess_99",                 // optional
  "provider": "anthropic"                  // optional
}
json
200 OKSkill response
# POST /api/skills/code_review/execute — response
{
  "skill": "code_review",
  "output": {
    "summary": "2 security issues, 3 style improvements.",
    "findings": [
      {
        "severity": "high",
        "category": "security",
        "line": 1,
        "message": "Credentials sent over unencrypted fetch().",
        "suggestion": "Use HTTPS and never inline credentials."
      },
      {
        "severity": "medium",
        "category": "style",
        "line": 1,
        "message": "Function parameters are single letters.",
        "suggestion": "Rename to (username, password)."
      }
    ],
    "score": 62,
    "passed": false
  },
  "tokens": { "input": 184, "output": 312 },
  "duration_ms": 2480,
  "request_id": "req_8f3a2b"
}
json

Ready to build?

Spin up a local OpenForge in under 60 seconds, then start hitting the API. All endpoints work identically on localhost and in production.