# Kollabor Engine API Spec

## Overview

The Kollabor Engine runs as a local HTTP server exposing the full AI engine
(conversation, tool execution, permissions, hooks, MCP) over a clean REST + SSE API.

Consumers:
- CLI: imports Python packages directly OR calls local socket (no change needed)
- Tauri app: Rust IPC to local HTTP (replaces broken anthropic.rs/chat.rs/mcp.rs)
- Web UI: browser calls same HTTP endpoints (SSE for streaming)

The engine IS the source of truth. Clients are dumb renderers.


## Transport

Base URL: http://127.0.0.1:{PORT}
Default port: 7433 (configurable, auto-selects free port)

Auth: bearer token generated on startup, written to
~/.kollabor-cli/engine.token
Clients read this file to authenticate. Rotates every session.
Local-only binding (127.0.0.1) so no network exposure.

Content-Type: application/json for REST, text/event-stream for SSE.


## Session Lifecycle

A session = one conversation context. Multiple sessions can run concurrently
(multiple tabs in web UI, CLI + app simultaneously).

```
POST /sessions                    create session
GET  /sessions                    list active sessions
GET  /sessions/{id}               session info + stats
DELETE /sessions/{id}             end session, flush logs
```

### POST /sessions

Request:
```json
{
  "profile": "default",
  "system_prompt": null,
  "system_prompt_file": null,
  "agent": null,
  "workspace": "/path/to/project",
  "approval_mode": "confirm_all",
  "mcp_servers": ["memory", "filesystem"],
  "metadata": {}
}
```

Response:
```json
{
  "session_id": "sess_abc123",
  "profile": { ... },
  "approval_mode": "confirm_all",
  "mcp_servers": [...],
  "created_at": "2026-02-17T12:00:00Z"
}
```

approval_mode values: confirm_all | default | auto_approve_edits | trust_all


## Sending a Message (Core Turn)

```
POST /sessions/{id}/message
```

Request:
```json
{
  "content": "refactor this function",
  "attachments": [],
  "continuation": false
}
```

Response: SSE stream (text/event-stream)

The stream stays open for the entire turn including all tool calls.
Close it when you receive a `turn_complete` or `error` event.


## SSE Event Types

All events: `data: {json}\n\n`
All events include: `{ "type": "...", "session_id": "...", "ts": 1234567890 }`

### token
Streaming text output from the LLM.
```json
{ "type": "token", "text": "Here is the refactored" }
```

### thinking
Extended thinking content (Claude 3.7+ thinking mode).
```json
{ "type": "thinking", "text": "Let me analyze the function..." }
```

### tool_start
Engine is about to execute a tool. If approval_mode requires it,
a permission_request follows immediately after. Otherwise tool runs.
```json
{
  "type": "tool_start",
  "tool_id": "tool_xyz",
  "tool_name": "str_replace_editor",
  "tool_type": "file_edit",
  "input": { "path": "src/main.rs", "old_str": "...", "new_str": "..." },
  "risk_level": "medium"
}
```

risk_level: low | medium | high | critical

### permission_request
Engine is PAUSED. Tool will not run until client responds.
Show approval UI, then POST to /sessions/{id}/permission.
```json
{
  "type": "permission_request",
  "tool_id": "tool_xyz",
  "tool_name": "str_replace_editor",
  "tool_type": "file_edit",
  "input": { ... },
  "risk_level": "medium",
  "risk_reason": "modifies source file",
  "expires_at": 1234567890
}
```

### permission_granted / permission_denied
Echoed back after client responds. Engine resumes or skips tool.
```json
{ "type": "permission_granted", "tool_id": "tool_xyz", "scope": "once" }
{ "type": "permission_denied",  "tool_id": "tool_xyz" }
```

scope (on granted): once | session | project | always_edits | trust_tool

### tool_result
Tool finished executing.
```json
{
  "type": "tool_result",
  "tool_id": "tool_xyz",
  "tool_name": "str_replace_editor",
  "success": true,
  "output": "File updated successfully",
  "execution_time": 0.12,
  "metadata": { "diff": "..." }
}
```

### hook_event
A hook fired. Informational - clients can display in activity log.
```json
{
  "type": "hook_event",
  "hook_name": "pre_api_request",
  "plugin": "hook_monitoring_plugin",
  "result": "pass"
}
```

### question_gate
LLM asked a clarifying question. Engine is suspended waiting for user reply.
Functionally same as turn_complete but signals "send another message to continue".
```json
{
  "type": "question_gate",
  "question": "Which file do you want me to refactor?",
  "pending_tools": 3
}
```

### turn_complete
Turn is done. Stream can be closed.
```json
{
  "type": "turn_complete",
  "input_tokens": 1240,
  "output_tokens": 384,
  "thinking_tokens": 128,
  "tool_calls": 2,
  "stop_reason": "end_turn"
}
```

### error
Something blew up. Stream closes after this.
```json
{
  "type": "error",
  "code": "rate_limit",
  "message": "Rate limit hit, retry in 30s",
  "retryable": true
}
```

error codes:
  rate_limit | auth_error | context_exceeded | tool_failed
  mcp_unavailable | cancelled | internal


## Permission Response

Called while a permission_request is pending on the SSE stream.

```
POST /sessions/{id}/permission
```

```json
{
  "tool_id": "tool_xyz",
  "decision": "approve",
  "scope": "session"
}
```

decision: approve | deny
scope (on approve): once | session | project | always_edits | trust_tool

Engine resumes, emits permission_granted or permission_denied on the SSE stream.


## Cancel Turn

```
POST /sessions/{id}/cancel
```

Cancels in-flight LLM request and any pending tool execution.
Emits `{ "type": "error", "code": "cancelled" }` on the stream.


## Conversation History

```
GET  /sessions/{id}/history          full conversation
GET  /sessions/{id}/history?limit=10 last N turns
DELETE /sessions/{id}/history        clear history
```

History item:
```json
{
  "role": "user" | "assistant",
  "content": "...",
  "ts": 1234567890,
  "tool_calls": [...],
  "token_usage": { ... }
}
```


## Profiles

```
GET    /profiles              list all profiles
GET    /profiles/{name}       get profile detail
POST   /profiles              create profile
PUT    /profiles/{name}       update profile
DELETE /profiles/{name}       delete profile
POST   /profiles/{name}/test  test API key + connectivity
```

GET /profiles response:
```json
{
  "profiles": [
    {
      "name": "default",
      "provider": "anthropic",
      "model": "claude-sonnet-4-6",
      "active": true
    }
  ],
  "active": "default"
}
```

POST /sessions/{id}/profile  - switch profile mid-session
```json
{ "profile": "gpt4" }
```


## MCP Server Management

```
GET    /mcp/servers               list configured servers
POST   /mcp/servers               add server
DELETE /mcp/servers/{name}        remove server
POST   /mcp/servers/{name}/connect    connect
POST   /mcp/servers/{name}/disconnect disconnect
GET    /mcp/servers/{name}/tools  list tools for server
```

POST /mcp/servers:
```json
{
  "name": "memory",
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-memory"],
  "env": {}
}
```

MCP server status: disconnected | connecting | connected | error


## Permissions Management

```
GET  /sessions/{id}/permissions           current mode + stats
POST /sessions/{id}/permissions/mode      set approval mode
GET  /sessions/{id}/permissions/approvals session + project approvals
POST /sessions/{id}/permissions/clear     clear session approvals
```

POST /sessions/{id}/permissions/mode:
```json
{ "mode": "trust_all" }
```


## System Prompt

```
GET  /sessions/{id}/system-prompt         get current prompt
POST /sessions/{id}/system-prompt/rebuild rebuild (after agent/plugin change)
```

The engine handles trender tags, agent loading, plugin additions internally.
Clients don't need to manage system prompt content.


## Engine Status

```
GET /health         liveness check
GET /status         engine info + all session summaries
GET /version        engine version + package versions
```

GET /status:
```json
{
  "version": "0.5.0",
  "sessions": 2,
  "uptime": 3600,
  "providers": ["anthropic", "openai"],
  "mcp_servers": { "memory": "connected", "filesystem": "connected" }
}
```


## Serve Mode

Engine is started with:
```
python -m kollabor_engine serve --port 7433 --log-level info
```

Or programmatically:
```python
from kollabor_engine import EngineServer
server = EngineServer(port=7433)
await server.start()
```

On startup:
- Generates auth token, writes to ~/.kollabor-cli/engine.token
- Binds to 127.0.0.1:{port}
- Loads profiles + MCP config
- Emits ready signal (stdout: "READY:{port}")
  Tauri/CLI can watch stdout for this before connecting.


## Rust Client (Tauri)

Rust IPC client pattern:
1. Spawn python process, watch stdout for "READY:{port}"
2. Read token from ~/.kollabor-cli/engine.token
3. All AI calls → HTTP to 127.0.0.1:{port} with Bearer token
4. Stream SSE events, emit to Vue frontend via Tauri event system
5. Permission requests: pause, show native UI, POST decision back

Tauri wraps the engine as a managed sidecar:
- `src-tauri/src/commands/engine.rs` - spawn + monitor process
- `src-tauri/src/commands/ai.rs`     - thin proxy to engine HTTP
- Replaces: anthropic.rs, chat.rs, mcp.rs, tool_runner.rs, xml_tool_parser.rs


## Web UI

Browser calls engine directly (same endpoints).
Works because engine binds locally - no CORS issues for same-machine web.
For hosted web: add a proxy layer (nginx/caddy) + proper auth.


## Implementation Plan

Phase 1: Engine server wrapper
  - FastAPI app wrapping existing kollabor-ai + kollabor-agent
  - Session management (multiple concurrent sessions)
  - SSE streaming adapter (current streaming → SSE events)
  - Auth token generation

Phase 2: Tauri integration
  - engine.rs sidecar manager
  - ai.rs HTTP proxy commands
  - Remove anthropic.rs, chat.rs, mcp.rs, tool_runner.rs, xml_tool_parser.rs

Phase 3: Web UI
  - Vue composables calling engine directly
  - SSE event handling in frontend
  - Permission UI component

Phase 4: CLI migration (optional)
  - CLI can keep importing Python directly forever
  - Or switch to local socket for consistency
