Show navigation
Host Installer
The host started only as pnpm dlx agent-console-server in a terminal, which asked a reader to have Node and pnpm and to know what a terminal is. A web page cannot install or start a program on the reader's machine — the browser's sandbox exists to forbid exactly that — so the one step that cannot be removed is a single download, and it is made as small as it can be for the least technical reader (simplest reader first). T3 Code makes the same split: an app runs its backend, and the command stays for anyone who wants it (T3 Code).
How it works
- One Windows file, carrying everything.
pnpm build:seain the package bundlessrc/cli.tsand every dependency into one file (tsdown.sea.config.ts), copies the SDK's ownclaude.exeand node-pty's Windows files next to it (packages/agent-console-server/scripts/copyClaudeCodeExecutable.ts,packages/agent-console-server/scripts/copyNodePty.ts), and embeds them intoagent-console-host.exewith Node's--build-sea, each as an asset of the configurationpackages/agent-console-server/scripts/writeSeaConfig.tswrites from what was placed. It is one file rather than a zip because Windows lets a reader open a program from inside a zip without the files beside it, which is the first thing the reader would try. It is built for Windows alone, and unsigned: signing and the other platforms each cost a yearly fee (signed host installers). - It is attached to every release. The release workflow's
host-installerjob builds it on Windows and attaches the executable to the release, and the pairing screen links the newest one (HOST_INSTALLER_URL). The repository has immutable releases on, so a published release takes no new asset: the workflow creates the release as a draft, attaches the host to it, and publishes it last, so the newest release always has the executable on it. - Opening it installs it. Run from anywhere but its install folder, the executable copies itself to
%LOCALAPPDATA%\Esposter\Host, writes out the Claude Code binary and node-pty it carries beside the copy (shell pane), and registers theesposter-hostscheme in the user's own registry classes, so no administrator is asked (installHost). It then serves from the window it was opened in, as the installed host would. An install that cannot finish — most often an older host still running from the install folder, whose files Windows keeps locked — says what to do in plain words and exits. Inside the executable the SDK cannot find its own binary, which it looks up beside its module, sogetClaudeCodeExecutablePathnames the installed one; run from the package, the SDK finds its own. - Its window speaks plainly. It says the host is running and to keep the window open, and that closing the window stops it. Opened from the download, it also says to press Connect on the page, with a one-time link to hold Ctrl and click instead (device pairing). No address, port or credential is shown.
- A link starts it. Opening
esposter-host://…starts the installed executable with the link as its argument (getSchemeLaunch), after the browser's own Open Esposter Host? prompt, which no page can skip. A console program started that way gets a console window of its own, which Windows 11 opens in Terminal, so the host runs where the reader can see it and closing that window stops it (host). A link can only start the host, never configure it. Any site can open anesposter-host://link, and Windows passes it as"%1", so a link carrying a quote would close that argument early and smuggle in flags of its own —--originmaking the attacker's site the one origin allowed to pair. A launch holding a link and anything else is refused before any argument is read (checkIsSchemeLaunchTampered). A link opened while a host already runs finds the port taken, has what holds it prove it is the host, and — when it is — hands it the link's pairing code, says it is running in another window and closes, leaving the page to the running one; a port some other program holds is never handed the code, is reported as that, and the host exits with a failure (sendToRunningHost). agent-console-host.exe uninstallremoves the scheme at once and the install folder a moment after the window closes, through a detached PowerShell that reads the folder from its environment as a literal path, since a running executable cannot delete itself on Windows.
flowchart TD
D[Download the host] --> R[Open agent-console-host.exe]
R --> I{In the install folder?}
I -->|no| C[Copy itself, write out claude.exe, register esposter-host]
C --> S[Serve in this window]
I -->|yes| S
S --> K[The window says the host is running]
L["A page opens esposter-host://"] --> P[Browser asks: Open Esposter Host?]
P --> W[Windows starts the host in a new console window]
W --> T{Port free?}
T -->|yes| S
T -->|no| H{The host holds it?}
H -->|yes| E[Hands it the code, says a host is already running, and closes]
H -->|no| F[Says another program has the port, and fails]
What is deliberately not in it
- No signing, and no macOS or Linux build. Each costs a yearly fee; both are deferred.
- No desktop window and no background service. The console is the page and the host's console window is its only other surface, where T3 Code's desktop app is its whole interface. It does not start at login or hide in a tray, since a process the reader cannot see is one they cannot stop.
- No updater of its own yet. Opening a newer download installs over the old one once the old host's window is closed; an updater comes when releases are frequent enough to make that a chore.
Key files
| File | Role |
|---|---|
packages/agent-console-server/tsdown.sea.config.ts | The host bundled into one file with every dependency |
packages/agent-console-server/scripts/copyClaudeCodeExecutable.ts | The SDK's Windows Claude Code binary, placed for the executable to embed |
packages/agent-console-server/scripts/writeSeaConfig.ts | The executable Node's --build-sea makes, with every placed file an asset |
packages/agent-console-server/src/services/cli/installDownloadedHost.ts | Installs a download before it serves |
packages/agent-console-server/src/services/cli/commands/agentConsoleServerCommand.ts | Takes a scheme link, and the commands uninstall among them |
packages/agent-console-server/src/services/installer/installHost.ts | The copy, the Claude Code binary written out, and the scheme in the registry |
packages/agent-console-server/src/services/installer/checkIsSchemeLaunchTampered.ts | A link launch carrying more than the link, refused |
packages/agent-console-server/src/services/installer/getSchemeLaunch.ts | What an esposter-host:// link asked for |
packages/agent-console-server/src/services/server/sendToRunningHost.ts | Whether the host is what holds a taken port, and the code handed to it |
packages/agent-console-server/src/services/installer/getClaudeCodeExecutablePath.ts | The installed Claude Code binary, inside the executable |
packages/agent-console-server/src/services/drivers/claudeAgentSdk/createSessionOpener.ts | Passes that binary to the SDK |
.github/workflows/Release.yaml | Builds the Windows host and attaches it to the release |
apps/web/app/components/AgentConsole/Panel/Pairing.vue | The steps with the download, and Connect as the last |
Sources
- Node.js — single executable applications —
--build-seasince v25.5.0, assets embedded beside the main script, and native addons needing a real file to load from. - T3 Code — an app running the backend behind its web interface, with the command kept beside it.
Scroll to top