All endpoints are served on the gateway (default port 30100).
Request/response bodies are JSON unless noted. Streaming endpoints use text/event-stream.
Interactive docs available at: http://localhost:30100/docs
Returns gateway status and loaded modules.
This endpoint is the capability probe used by framework plugins. In http+plugin
mode the modules list is the contract that tells a plugin whether skill,
memory, rl, or proxy is actually active.
Response:
{
"status": "ok",
"modules": ["proxy", "skill", "memory", "rl"],
"uptime_sec": 42
}302 redirect to /v1/health (backward compat for old monitoring scripts).
Retrieve last trajectory for a session.
Response: Trajectory JSON | 404
Delete session persistence data.
Response: {"deleted": true} | 404
These routes are only available when proxy is present in gateway.enabled_modules.
OpenAI-compatible chat endpoint. Runs full Pre/Post pipeline.
Headers:
| Header | Description |
|---|---|
X-Session-Id |
Session identifier (auto-generated if absent) |
X-Agent-Type |
Agent framework: openclaw, copaw, ironclaw, picoclaw, claude_code |
X-Turn-Type |
main (default) / side / eval — only main generates RL training data |
X-Session-Done |
1 marks session end (triggers skill evolution check) |
Request body: Standard OpenAI ChatCompletion request
Response: Standard OpenAI ChatCompletion response (streaming or non-streaming)
Anthropic Messages API compatible endpoint.
Headers: Same as /v1/chat/completions plus x-api-key (Anthropic-style auth)
Returns available models from configured providers.
These routes are available in both transport modes:
proxymode: the gateway pipeline calls them internally.http+pluginmode: framework plugins call them directly.
Retrieve relevant skills for the current request.
Request:
{
"session_id": "sess-abc123",
"messages": [{"role": "user", "content": "Debug this Python code"}],
"model": "gpt-4o",
"metadata": {
"agent_type": "claude_code",
"images": []
}
}Response:
{
"additional_context": "# Skills\n\n## debug-systematically\n...",
"messages": null,
"model": null,
"metadata": {
"injected_skills": ["debug-systematically", "codebase-navigation"],
"skill_generation": 3,
"retrieval_mode": "template"
}
}Submit trajectory for skill evolution analysis.
Request:
{
"session_id": "sess-abc123",
"trajectory": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}],
"metadata": {
"success": false,
"skill_generation": 3,
"agent_type": "claude_code"
}
}Response: {"status": "accepted", "queued_for": ["skill"], "metadata": {"buffered": 4}}
List all loaded skills.
Response: [{"name": "debug-systematically", "description": "...", "category": "coding", ...}]
Reload skills from disk.
Response: {"loaded": 12, "path": "visualclaw/skills_seed/seed_universal_mc"}
Manually trigger skill evolution.
Request: {"failed_samples": [{"prompt": "...", "response": "..."}]} (omit to use buffered samples)
Response: {"new_skills": ["new-skill-name"], "generation": 4}
These routes are available in both transport modes and are the primary API surface for plugin-driven integrations.
Retrieve relevant memories for the current request.
Request: Same structure as /v1/skill/inject with optional top_k in metadata.
Response:
{
"additional_context": "# Relevant Memory\n\nUser prefers TypeScript over JavaScript...",
"metadata": {
"retrieved": [{"id": "sess-abc_2024...", "summary": "...", "timestamp": "..."}]
}
}Store session summary in memory.
Request: Same as skill/collect.
Response: {"status": "accepted", "metadata": {"memory_id": "sess-abc_2024-01-01T..."}}
Manual memory search.
Request: {"query": "TypeScript preferences", "top_k": 5, "session_id": null}
Response: [{"id": "...", "summary": "...", "timestamp": "..."}]
Get user memory file content.
Response: {"content": "# User Memory\n\n...", "path": "/path/to/user_memory.md"}
Append to user memory file.
Request: {"content": "User prefers concise responses."}
Response: {"status": "ok"}
Get all memory entries for a session.
Delete session memory entries.
Response: {"deleted": 3}
Deduplicate memory entries.
Response: {"before": 150, "after": 120, "duration_ms": 45}
Resolve current best model (for model hot-swap after training).
Request: Same structure as inject endpoints.
Response:
{
"model": "ft:gpt-4o-2024-...",
"provider": {"provider_type": "openai"},
"metadata": {"switched": true}
}Submit trajectory for RL training.
Note: turn_type in metadata defaults to "main" if absent (Plugin direct mode).
Request:
{
"session_id": "sess-abc",
"trajectory": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}],
"metadata": {
"turn_type": "main",
"skill_generation": 3,
"agent_type": "openclaw"
}
}Response: {"status": "accepted", "queued_for": ["rl"], "metadata": {"queue_size": 2}}
RL trainer status.
Response:
{
"active_model": "ft:gpt-4o-...",
"queue_size": 2,
"success_rate": 0.75,
"total_steps": 10,
"training": false,
"skill_gen": 3
}Manually trigger a training step.
Response: {"status": "triggered"} | {"status": "already_running"}
Update active model after external training.
Request: {"model": "ft:gpt-4o-...", "provider": "openai"}
Response: {"status": "ok", "previous_model": "gpt-4o"}
Manual PRM scoring.
Request: {"prompt": "...", "response": "...", "images": []}
Response: {"score": 1.0, "votes": [1, 1, 1], "eval_text": "Score: 1 — helpful"}
Extract images, optionally describe them, normalize format.
Request metadata fields:
target_format:preserve(default) /openai/anthropicgenerate_descriptions:trueto describe images via VLM
Response: PreResponse with additional_context (visual descriptions) + normalized messages.
Manually describe images.
Request: {"images": [{"url": "https://...", "media_type": "image/jpeg"}]}
Response: {"descriptions": ["A chart showing quarterly revenue..."]}
WebSocket for continuous video frame stream.
Client → Server:
{"session_id": "cam-001", "features_128": [0.1, -0.3, ...], "jpeg_b64": "<base64>", "timestamp": "2024-01-01T..."}Server → Client:
{"gate": "MAJOR", "description": "User is pointing at a whiteboard diagram", "keyframe_count": 3}gate values: SKIP (duplicate frame) / MINOR (update state) / MAJOR (VLM called)
Current video state for a session.
Response: {"keyframe_count": 3, "latest_description": "...", "last_update": "..."}
Clear video state memory for a session.
Response: {"enabled": true, "total_cost": 0.023, "rules_loaded": 9}
Check request against constitution rules.
Returns 403 if blocked. Otherwise returns PreResponse with {"allowed": true} metadata.
Response: {"active": true, "mode": "sleep_window", "calendar_enabled": false}
Start or stop the background scheduler.
Gateway WebSocket for glasses companion app (same protocol as dedicated port 8765).
Client → Server: Binary JPEG bytes or JSON {"type":"frame"/"audio","data":"<base64>"}
Server → Client: (Currently receive-only; responses via Gemini Live separate channel)
HTTP-triggered Gemini Live query.
Request: {"session_id": "...", "prompt": "What am I looking at?", "images": []}
Response: {"response": "You're looking at a circuit board..."}
Latest scene description for a session.
Response: {"connected_clients": 1, "glasses_bridge_port": 8765, "glasses_connected": true, ...}
{
"session_id": "string",
"messages": [{"role": "user|assistant|system", "content": "string|list"}],
"model": "string",
"metadata": {}
}{
"additional_context": "string",
"messages": null,
"model": null,
"provider": null,
"metadata": {}
}{
"session_id": "string",
"trajectory": [{"role": "...", "content": "..."}],
"metadata": {}
}{
"status": "accepted|skipped|error",
"queued_for": ["skill"],
"metadata": {}
}