A loaded session is wasted if the only way in is the keyboard.

A Claude Code session is already loaded with a project, its files, and its instructions, yet it is normally a sealed loop: a person types, the model answers, and nothing else can reach in. Wiring an outside event to a session meant building bespoke plumbing for each source and teaching the session about it.

ae-channel is the load-bearing core salvaged from a larger, now-decommissioned messaging system, reduced to the one capability that earned its keep. It runs as one small server that Claude Code spawns alongside each session, so nothing lives in the background and nothing has to stay alive between uses. One rule governs it: the pipe is dumb. The server carries bytes and never tries to understand them.

One small server per session, two halves, no daemon and no broker.

Claude Code spawns a copy alongside each session. Two decoupled halves are wired by a thin composition root that owns the single routing decision; neither half knows the other's job. Two plain files on disk do all the coordinating.

Anatomy ae-channel
01 Lifetime
One server spawned per session; nothing in the background, nothing kept alive between uses
02 Channel half
Speaks the Model Context Protocol into the session; routing arrives as a callback
03 HTTP half
A plain ingress any caller can reach, plus the outbound event stream
04 Composition root
Wires the two halves and owns the one routing decision
05 Registry
A shared file of who is online and where to reach them
06 Spool
A per-session holding file for messages to offline peers

One server, two halves, a single decision: deliver, or spool for later.

Two halves wired by a thin composition root, one speaking the Model Context Protocol into the session, one a plain HTTP ingress any caller can reach. Between them sits the only routing decision in the whole system.

The channel ae-channel
Traffic reach a live session
Inbound · HTTP
01 POST /inject
raw text or JSON { content, meta }
02 Address
stray sender assigned a stable ext-N chat_id
03 Inject
fires a claude/channel notification
04 Surface
Claude Code renders it as a tag
send() · the routing fork
01 Live peer
delivered straight into the peer → live
02 Offline / unknown
broadcast to watchers + set aside in the spool → queued
03 Drain
replayed in order on the peer's next boot
Verdict live / queued

Two tools the session calls, three endpoints any caller hits, over one dumb pipe.

The session sees two tools; the outside world sees three HTTP endpoints. Everything that crosses the seam is forwarded verbatim, never read, so a new source just points at the ingress and works.

What it gives you ae-channel
send
Message a session by name, or reply by inbound id.
peers
The sessions currently online.
POST /inject
Any caller pushes a message in.
Dumb pipe
Forwards bytes, never reads them.
GET /events
An outbound stream of the session's replies.
Survives offline
Held and replayed in order on next boot.
Per session
Spawned per session; nothing runs between uses.

Meaning lives at the edges, never in the middle.

The discipline that keeps the surface small is a refusal: the server never decides what a message means. That question is pushed out to the two places it belongs, the payload itself and the receiving session's own instructions about how to react.

The pipe stays dumb ae-channel
Without it
Teach the server what messages mean, and every new source becomes a change to the server.
With ae-channel
Keep the server blind to meaning, and a new source just points at the ingress and works.
work