---
name: treehouse-hooks
description: INVOKE THIS FIRST when integrating an app or service with the Treehouse hooks HTTP API — calling the agent programmatically, streaming responses, fire-and-forget agent tasks, warm containers, or session-based isolated workspaces. Use when building apps that POST to /hooks/invoke, /hooks/stream, /hooks/agent, /hooks/warm, or /hooks/wake.
---

# Treehouse Hooks API

The hooks system lets any app call your agent over HTTP. All endpoints share the same base URL and bearer token:

```
Base URL:      https://{tenant}.devitltd.uk
Authorization: Bearer <hooks-token>
Content-Type:  application/json
```

Get your token: `tc hooks` — enable if needed: `tc hooks enable`.

---

## Endpoints at a glance

| Endpoint | Style | Use case |
|---|---|---|
| `POST /hooks/invoke` | Sync (wait for result) | Simple request/response |
| `POST /hooks/stream` | SSE streaming | Real-time output, long responses |
| `POST /hooks/agent` | Fire-and-forget | Background agent tasks |
| `POST /hooks/warm` | Pre-warm | Start a container before the first call |
| `POST /hooks/wake` | Scheduled heartbeat | Trigger agent from HEARTBEAT.md |

---

## Common request fields

All endpoints accept these fields in the JSON body:

| Field | Type | Description |
|---|---|---|
| `prompt` | string | The message to send to the agent. Required (or use `tool`). |
| `tool` | string | Call a specific agent tool by name instead of a prompt. |
| `args` | object | Arguments for the `tool` call. |
| `session` | UUID string | Session identifier — see Session & keepAlive below. |
| `keepAlive` | boolean | Keep the container warm after the call (requires `session`). |
| `attachments` | array | Files to send to the agent — see Attachments below. |

---

## POST /hooks/invoke — synchronous

Blocks until the agent responds (max 90 seconds), then returns the result.

```json
{ "prompt": "Summarise the attached document", "attachments": [...] }
```

**Response:**
```json
{ "ok": true, "result": "Agent response text" }
```

Error responses: `400` bad request · `403` tool not allowed · `504` timeout exceeded.

---

## POST /hooks/stream — SSE streaming

Returns a `text/event-stream` immediately. Events arrive as the agent types.

```json
{ "prompt": "Write me a poem", "session": "uuid", "keepAlive": true }
```

**SSE events (in order):**

```
event: open
data: {"ok":true}

event: progress        ← optional mid-run status messages
data: {"text":"..."}

event: text            ← streaming output chunks
data: {"text":"..."}

event: result          ← final complete response
data: {"ok":true,"result":"Full agent response"}

event: error           ← only on failure
data: {"ok":false,"error":"..."}
```

Parse with the browser `EventSource` API or any SSE client library. No timeout — connection stays open until the agent finishes.

---

## POST /hooks/agent — fire-and-forget

Queues the prompt and returns `202` immediately without waiting for a result. Use for background tasks where you don't need the response synchronously.

```json
{ "prompt": "Process the overnight report", "session": "uuid" }
```

**Response:**
```json
{ "ok": true, "queued": true }
```

With a `session` UUID, creates a fully isolated agent workspace at `{tenant}/hook-{uuid}` — its own group directory, IPC queue, and session history. Useful for spawning independent sub-agents.

---

## POST /hooks/warm — pre-warm a container

Starts an agent container in the background so it's ready before the first real call. Eliminates cold-start latency.

```json
{ "session": "uuid" }
```

`session` (UUID) is **required**. The warm container is then reused by any subsequent `/hooks/invoke`, `/hooks/stream`, or `/hooks/agent` call with the same `session`.

**Response:**
```json
{ "ok": true, "session": "uuid", "warm": true }
```

If the container is already warm: returns `200` with `"existing": true`. Pre-warm at app startup, then use `keepAlive: true` on subsequent calls to keep it warm between requests.

---

## POST /hooks/wake — scheduled heartbeat trigger

Runs the agent using the content of `HEARTBEAT.md` in the group workspace as the prompt. Designed for scheduled/cron use cases.

No body required. Returns `202` immediately.

```
POST /hooks/wake
Authorization: Bearer <hooks-token>
```

Create `HEARTBEAT.md` in your group workspace with the standing instructions you want the agent to execute on each wake call.

---

## Session & keepAlive

Without a `session`, each call runs in a shared hook context — no conversation memory between calls.

With a `session` UUID:
- The call runs in an **isolated workspace** (`{tenant}/hook-{uuid}`) with its own conversation history
- Subsequent calls with the same UUID **continue the same conversation**
- Different UUIDs = completely separate agent instances

With `keepAlive: true` (requires `session`):
- The agent container stays running after the call
- The next call with the same `session` pipes directly into the warm container — no cold-start cost
- Use `POST /hooks/warm` to pre-warm before the first call

```json
{
  "prompt": "What did we discuss earlier?",
  "session": "550e8400-e29b-41d4-a716-446655440000",
  "keepAlive": true
}
```

---

## Attachments

Send files to the agent in any request body:

```json
{
  "prompt": "What is in this image?",
  "attachments": [
    {
      "name": "photo.png",
      "mimeType": "image/png",
      "data": "<raw base64 — NOT a data URL, strip the 'data:image/png;base64,' prefix>"
    }
  ]
}
```

`mimeType` determines how the agent receives the file:
- `image/*` → vision image
- `application/pdf` → document
- `text/*` → plain text
- `audio/*` → audio clip
- anything else → generic file

Multiple attachments supported. Strip the `data:...;base64,` prefix — send raw base64 only.

---

## Limits

- **Request body**: 20 MB max on all endpoints
- **Invoke timeout**: 90 seconds (`/hooks/invoke` only — `/hooks/stream` has no timeout)
- **Session**: must be a valid UUID v4 if provided
