# LLM Room Protocol Rooms are the bounded live-execution primitive in Abbotik. They are tenant-scoped, authenticated, and exposed as part of the `/llm/*` execution namespace. The API still owns the public root, docs, and `llms.txt` entrypoints; room execution is an LLM protocol layered on top of tenant data. ## Endpoints | Method | Path | Purpose | |--------|------|---------| | GET | `/llm/room` | List visible rooms | | POST | `/llm/room` | Rent a new room | | GET | `/llm/room/:id` | Fetch one room | | PATCH | `/llm/room/:id` | Update mutable room configuration | | POST | `/llm/room/:id/messages` | Inject one semantic room message | | POST | `/llm/room/:id/wake` | Wake a room explicitly | | GET | `/llm/room/:id/events` | Replay or follow room events as SSE | | GET | `/llm/room/:id/history` | Read durable room history | | POST | `/llm/room/:id/interrupt` | Interrupt an in-flight turn | | POST | `/llm/room/:id/release` | Release a room explicitly | ## Model A room is a rentable, tenant-scoped, bounded execution context for live LLM work. Current responsibilities: - room identity and tenancy - actor roster - room-local tool, wake, and done policy - bounded worker lifecycle - message history - event history - explicit wake, interrupt, and release verbs Current practical limits: - one worker per active room - one queued message at a time per room - deterministic event ordering within a room - one bounded actor turn per queued message Observed room lifecycle states: - `rented` - `active` - `idle` - `sleeping` - `releasing` - `released` - `failed` Important runtime guards: - released rooms reject new messages and wake requests - interrupt only succeeds while a turn is actively running - executor failures persist `room.last_error` and emit durable `error` events - PI-backed turns require exactly one user-scoped secret whose `metadata.provider` matches the actor provider; missing or duplicate matches fail closed with explicit room error codes - `GET /llm/room/:id/events` replays durable history first and only tails live events while the in-memory worker is still attached ## Internal Tool Catalog Rooms may expose internal LLM-executable tools when `tool_policy` grants access. These are not inbound user tool calls. They are native room tools resolved and executed inside the API runtime on behalf of the configured room actor. Current built-in tool families are: | Tool | Access | Purpose | Key arguments | |------|--------|---------|---------------| | `room.idle` | `full` | Request that the current room enter sleeping state after the active turn settles. | `reason` | | `room.release` | `full` | Request that the current room release itself after the active turn reaches a safe point. | `mode` | | `tool.ls` | `read` | List filesystem entries from the mounted runtime VFS. | `path`, `all`, `long`, `recursive`, `max_depth` | | `tool.cat` | `read` | Read one file from the mounted runtime VFS. | `path`, `encoding`, `max_chars` | | `tool.glob` | `read` | Match filesystem paths from the mounted runtime VFS using glob-style patterns. | `pattern`, `cwd`, `all`, `type`, `max_depth` | | `tool.mkdir` | `edit` | Create one directory in the mounted runtime VFS. | `path`, `parents` | | `tool.rm` | `edit` | Remove one file or directory from the mounted runtime VFS. | `path`, `recursive`, `force` | | `tool.mv` | `edit` | Rename or move one path within the mounted runtime VFS. | `source`, `destination` | | `curl.get` | `read` | Fetch one URL with HTTP GET and return the raw response. | `url`, `headers`, `timeout_ms` | | `curl.post` | `read` | Fetch one URL with HTTP POST and return the raw response. | `url`, `headers`, `body`, `timeout_ms` | | `curl.markdown` | `read` | Fetch one URL and return a deterministic markdown-style extraction. | `url`, `headers`, `timeout_ms`, `max_chars` | | `curl.compact` | `read` | Fetch one URL and return a deterministic compact representation. | `url`, `headers`, `timeout_ms`, `max_chars` | | `curl.summarize` | `read` | Fetch one URL, preprocess it deterministically, then summarize it with a lightweight model. | `url`, `headers`, `timeout_ms`, `focus`, `max_chars` | | `describe.model_get` | `read` | Read one model definition from the tenant-local Describe surface. | `model` | | `find.records` | `read` | Run one structured find query against a model. | `model`, `query` | | `find.filter` | `read` | Load and run one saved find filter. | `model`, `target` | | `aggregate.query` | `read` | Run one aggregate query against a model. | `model`, `query` | | `data.get` | `read` | Read one record by id from a model. | `model`, `id` | | `data.list` | `read` | List records from a model. | `model`, `limit`, `offset`, `trashed` | | `data.create` | `edit` | Create one record in a model. | `model`, `record` | | `data.update` | `edit` | Update one record in a model. | `model`, `id`, `record` | | `data.delete` | `edit` | Delete one record from a model. | `model`, `id` | Notes: - filesystem tools operate on the mounted runtime VFS exposed through the room runtime, not a host shell working directory - room lifecycle tools mutate the room itself and therefore require `full` tool access - `curl.markdown` and `curl.compact` are deterministic programmatic transforms - `curl.summarize` uses a separate lightweight model pass and does not recurse across discovered links - tool availability is still gated by the room's `tool_policy` ## Storage In the API service, room state is stored durably in tenant-local `rooms`, `room_messages`, and `room_events` models through direct `Database.*` calls inside the same process. There is no loopback HTTP bridge between the LLM runtime and the data layer. ## Factory Boundary Rooms are the execution primitive. Factory orchestration is now the sibling `/llm/factory` route family in this service. Use rooms for bounded live turns, and use factory when the work needs durable planning, issue tracking, verification, and review state across a run.