How plugs wrap a session
The chain of handlers, the run lifecycle, the message proxy and where each message is recorded.
One chain, three handlers
Plugs nest in the order of setup: the first plug wraps all the others. Each handler receives a
next function that runs everything inside it, and the code around that call is where the plug does
its work.
Before next() a plug attaches: it creates or re-attaches what it needs and shapes the agent's
command, directory and environment. After next() it pauses. A run always ends in a pause, whatever
the reason, so a plug writes its pause code once, as the code after await next(). next() never
rejects: a failure of an inner plug arrives as a pause with the reason failed.
When the session cannot resume, the chain runs again for teardown, in the same process: only plugs
with an onTeardown take part, outermost first, and each destroys what it created after its inner
plugs have.
Runs
A session is a series of runs. A start run creates the environment; a resume run, after a pause,
re-attaches to it; a teardown run only destroys it. A plug asks ctx.run.kind only where the runs
differ: often "create unless it exists" covers both start and resume.
Messages
The agent talks to the runner in the Agent Client Protocol, as JSON-RPC over the agent's stdio. The runner sits on that stream as a proxy, so every method, including the ones the SDK does not know, passes through one mechanism that does not care whether the stream is a local pipe or a remote channel.
Messages whose method the ACP SDK types reach onMessage, in both directions. Messages to the
agent flow through plug 1 first; messages from the agent flow through the last plug first, so the
outermost plug has the last word on what reaches Blaise.
A message is recorded where it leaves the chain: what the agent sees (including text a plug injected) and what Blaise receives (after redaction). A request that a plug answers itself is recorded too, tagged with the plug's name. History replayed when a session is loaded again is shown to the plugs but not recorded a second time.
Hosts
Plugs act on the agent's machine through ctx.host, not through Node's fs and child_process. A
plug can pass a different host to next({ host }), and every plug after it, and the agent, then
runs there. Hosts connect when first used, and the runner closes the host when the next() that
introduced it resolves. The file system of every host has the node:vfs interface, and the local
host is the real file system, so a plug is written once for a laptop and for a container.
Isolation
Each session runs in a process of its own. All plug code runs in that process, on the runner's machine, including the handlers of plugs listed below one that switches the host: only their effects happen on the host.
How sessions find a runner
Runners, instances, labels and requirements; how work is spread across instances; why work queues; and why a paused session goes back to the machine it ran on.
The life of a session
Runs, the environment between them, pause and resume, teardown, and why Blaise owns the clock.