diff --git a/Approaches.md b/Approaches.md
new file mode 100644
index 0000000..6679f8f
--- /dev/null
+++ b/Approaches.md
@@ -0,0 +1,153 @@
+# Approaches
+
+How does a **driver** (the primary Opus session, or an external event bus) deliver a
+message into an **already-running Claude Code worker** — *without* spawning a fresh
+`claude -p` per message? `claude -p` is deliberately **out of scope** here: it starts a
+new process (cold context, no live session) for every turn, which defeats the point of a
+persistent worker that holds `CLAUDE.md`, hooks, skills, MCP, and conversation state.
+
+That leaves four real transports. They differ on one decisive axis: **can the driver push
+into the session while it is idle/mid-run, or only at a turn boundary?**
+
+```mermaid
+flowchart TD
+ Q{"How is the message
delivered into a LIVE session?"}
+ Q -->|"HTTP request → terminal emulation"| AA["AgentAPI
(coder/agentapi)"]
+ Q -->|"streaming input generator (in-process)"| SDK["Agent SDK
streaming query()"]
+ Q -->|"worker PULLS on idle via a hook"| BUS["Message-queue
+ Stop-hook long-poll"]
+ Q -->|"raw keystrokes into the tmux pane"| TMUX["tmux send-keys
/ PTY paste"]
+
+ AA --> V1["✅ our leading choice"]
+ SDK --> V2["✅ if driver is our own code"]
+ BUS --> V3["⚠ async bus events only
(lands at turn boundary)"]
+ TMUX --> V4["⚠ fragile, but the raw primitive
AgentAPI wraps"]
+
+ classDef pick fill:#2f855a,stroke:#22543d,color:#ffffff;
+ classDef warn fill:#b7791f,stroke:#7b341e,color:#ffffff;
+ class AA,V1 pick
+ class BUS,TMUX,V3,V4 warn
+```
+
+*Figure: picking a delivery transport by how the message enters a running session.*
+
+## The native gap (why workarounds exist)
+
+Claude Code has **no first-class "inject a prompt into a running session"** API. It is an
+explicitly-requested, still-open feature:
+[#27441 — inter-agent message injection](https://github.com/anthropics/claude-code/issues/27441)
+and [#24947 — `claude inject`](https://github.com/anthropics/claude-code/issues/24947).
+Every approach below is a way around that gap. AgentAPI wins precisely because it
+productizes the sturdiest workaround (terminal emulation) behind a clean HTTP contract.
+
+## 1. AgentAPI — HTTP over terminal emulation *(leading)*
+
+[`coder/agentapi`](https://github.com/coder/agentapi) wraps the Claude Code **CLI** as an
+HTTP server and, under the hood, **drives the CLI's terminal** (it is essentially a
+hardened, stateful `tmux send-keys` with parsing). `POST /message` delivers a turn to the
+*running* session; `GET /events` (SSE) streams the reply. One session per server.
+
+- **Injects into a live session:** yes — this is its whole job.
+- **Subscription-safe:** the *primary* never sets `ANTHROPIC_BASE_URL`; only the worker's
+ wrapped `claude` launches with `ANTHROPIC_BASE_URL=https://ollama.ltms.dev` + bearer.
+- **Why chosen:** clean request/response contract, stable session, reply parsing solved —
+ none of the raw-keystroke fragility of doing it ourselves. See [[Architecture]].
+
+## 2. Agent SDK — streaming input *(good if the driver is our own code)*
+
+The Claude Agent SDK (TypeScript / Python) `query()` accepts a **streaming/async input
+generator**, so you can feed additional messages into a live query without respawning the
+process. This is the cleanest option **when the driver is a program you control** rather
+than another interactive Claude session — you get typed streaming events and permission
+callbacks instead of scraping a terminal.
+
+- **Injects into a live session:** yes, in-process.
+- **Trade-off:** the worker is an SDK-hosted loop, not a stock `claude` TUI — slightly
+ further from "a real Claude Code process" than AgentAPI, and the driver must be code.
+
+## 3. Message-queue + Stop-hook long-poll *(the genuinely hook-based path)*
+
+This is the **only pure-hooks** way to pull an external message into the **same** session,
+and the right fit when the trigger is an **asynchronous event bus** (NATS / Redis /
+webhook) rather than a synchronous driver waiting on a reply.
+
+```mermaid
+sequenceDiagram
+ participant CC as "Claude worker"
+ participant H as "Stop hook"
+ participant Q as "Queue (Redis / NATS)"
+ CC->>H: turn ends → Stop fires
+ H->>Q: long-poll (BRPOPLPUSH, ≤30s)
+ alt message arrives
+ Q-->>H: payload
+ H-->>CC: {"decision":"block","reason":""}
+ Note over CC: message injected as context → new turn
+ else timeout
+ Q-->>H: (nothing)
+ H-->>CC: allow stop (session idles cleanly)
+ end
+```
+
+*Figure: a `Stop` hook long-polls the bus and injects any message as the block `reason`.*
+
+- **Mechanism:** register a `Stop` hook that **long-polls** the queue for ~30s. On a hit it
+ returns `{"decision":"block","reason":""}` — the `reason` becomes injected
+ context and forces another turn. On timeout it lets the session stop. The
+ `stop_hook_active` flag guards against infinite loops.
+- **Reference implementation:** **Agent Room** (`agent-room-mcp`) — `Stop` +
+ `UserPromptSubmit` + `SessionStart` hooks over **Redis** "rooms" that Claude Code /
+ Cursor / Gemini CLI publish-subscribe to.
+ ([writeup](https://dev.to/agent-room/how-a-claude-code-stop-hook-unlocks-async-multi-agent-collaboration-no-polling-required-2e0e),
+ [DIY pattern](https://claudefa.st/blog/tools/hooks/stop-hook-task-enforcement)).
+- **Decisive limitation:** **pull-on-idle only** — the message lands at a **turn boundary**
+ (when the worker would otherwise stop), never mid-turn. Fine for "bus event wakes an idle
+ worker"; wrong for "interrupt a worker that's busy."
+- **Lighter cousin:** a `UserPromptSubmit` hook returning `{"additionalContext":"…"}`
+ (e.g. [claude-mem](https://docs.claude-mem.ai/hooks-architecture) pulling from a vector
+ DB) — but that fires only *when a prompt is submitted*, so it can't deliver an async push.
+
+## 4. tmux `send-keys` / PTY paste *(the raw primitive)*
+
+Inject keystrokes straight into the pane running `claude`. It is the most direct *push*
+into a live session and works today, but it is terminal automation — timing-sensitive,
+needs `capture-pane` to know when the worker is ready, and has no structured reply.
+Existing tools that do this (hooks only fire their *outbound* notification; injection is
+PTY/tmux):
+
+| Tool | Inbound injection | Hooks used for |
+|---|---|---|
+| [Claude-Code-Remote](https://github.com/JessyTsui/Claude-Code-Remote) (email/Telegram/Discord) | PTY smart-paste or `tmux send-keys` | outbound "task done" notify |
+| [OpenACP](https://dev.to/tigergethigher/how-to-control-claude-code-from-telegram-discord-or-slack-self-hosted-open-source-1jk8) (Slack/Discord/Telegram) | Agent Client Protocol bridge | — |
+| [samwize Slack monitor](https://samwize.com/2026/03/14/how-i-got-claude-code-to-monitor-slack-while-i-was-on-holiday/) | `tmux send-keys` | — |
+
+**AgentAPI is essentially this, productized** — which is why we prefer it over hand-rolled
+`send-keys`.
+
+## Research matrix
+
+| Approach | Transport | Inject into running session? | Async push (mid-idle)? | Subscription-safe (primary) | Reply parsing | Fragility |
+|---|---|---|---|---|---|---|
+| **AgentAPI** ✅ | HTTP → terminal emulation | ✅ | ✅ (`POST /message`) | ✅ (worker-only env) | ✅ SSE `/events` | Low |
+| **Agent SDK streaming** | in-process generator | ✅ | ✅ | ✅ | ✅ typed events | Low (but driver = code) |
+| **Queue + Stop-hook** | hook long-poll | ✅ (turn boundary) | ⚠ pull-on-idle only | ✅ | via `reason` text | Medium |
+| **tmux `send-keys`** | keystrokes / PTY | ✅ | ✅ | ✅ | ❌ scrape `capture-pane` | High |
+| ~~`claude -p`~~ (excluded) | new process/turn | ❌ (fresh session) | — | ✅ | ✅ | — |
+
+## Recommendation
+
+- **Primary Opus → worker (the bridge's main channel):** **AgentAPI** — synchronous,
+ parsed replies, clean subscription boundary. Selected. See [[Architecture]] / [[Setup]].
+- **External event bus → worker (async wake-ups):** layer a **Stop-hook long-poll** onto
+ the worker so bus events injected as `reason` resume it on idle. Complementary to
+ AgentAPI, not a replacement — different trigger shape.
+- **Avoid hand-rolled `tmux send-keys`** unless AgentAPI can't run; it's the same idea with
+ all the fragility left in.
+
+## Sources
+
+- [Hooks reference — Claude Code Docs](https://code.claude.com/docs/en/hooks)
+- [Agent Room — Stop-hook async collaboration](https://dev.to/agent-room/how-a-claude-code-stop-hook-unlocks-async-multi-agent-collaboration-no-polling-required-2e0e)
+- [Stop-hook task-enforcement pattern](https://claudefa.st/blog/tools/hooks/stop-hook-task-enforcement)
+- [claude-mem hooks architecture](https://docs.claude-mem.ai/hooks-architecture)
+- [coder/agentapi](https://github.com/coder/agentapi)
+- [Issue #27441 — inter-agent message injection](https://github.com/anthropics/claude-code/issues/27441) · [Issue #24947 — `claude inject`](https://github.com/anthropics/claude-code/issues/24947)
+- [Claude-Code-Remote](https://github.com/JessyTsui/Claude-Code-Remote) · [OpenACP guide](https://dev.to/tigergethigher/how-to-control-claude-code-from-telegram-discord-or-slack-self-hosted-open-source-1jk8)