Windows runs AO natively
ao start,ao stop,ao dashboard,ao spawn,ao doctor, andao updatenow have Windows paths.- Windows defaults to
runtime: processinstead of tmux. - Dashboard terminal works through the direct PTY server, not iTerm/tmux attach.
ConPTY is wrapped like tmux
- Each Windows session gets a detached
pty-hostprocess. - The host owns
node-pty+ ConPTY and exposes\\.\pipe\ao-pty-<sessionId>. - The mux WebSocket server relays xterm data to the named pipe.
Platform checks moved to helpers
isWindows,getShell,killProcessTree,findPidByPort, andgetEnvDefaultscentralize OS behavior.pathsEqualandcanonicalCompareKeystop Windows path identity bugs.- CI now runs Linux and Windows matrices for typecheck, tests, and web tests.
How The Windows Path Works
The key design is not "make tmux work on Windows." It is "keep AO's outer session model unchanged, then swap the terminal transport underneath."
ao start loads config and uses getDefaultRuntime().runtime-process instead of runtime-tmux.\\.\pipe\ao-pty-id: data, input, resize, status, kill.Behavior: Before vs Now
These are the user-visible outcomes of the branch. No repeated claims: each card maps to a specific implementation area.
1. Platform Adapter
The corrected direction is centralization: Windows branching lives in packages/core/src/platform.ts, not scattered call-site checks.
Platform assumptions were implicit
- Runtime selection and CLI startup were effectively tmux-first.
- Shell commands assumed Unix-ish execution more often than Windows PowerShell.
- Process tree kill, PID-by-port lookup, and env defaults were not one tested adapter surface.
One adapter owns OS behavior
getDefaultRuntime(): Windows returnsprocess, Unix returnstmux.getShell():AO_SHELL,pwsh, absolute Windows PowerShell, thencmd.exe.killProcessTree(),findPidByPort(), andgetEnvDefaults()cover Windows/POSIX differences behind tested helpers.
2. Runtime: tmux vs Process
This is the architectural center of PR #1025: keep AO's session model, replace the Windows terminal substrate.
ConPTY via node-pty + named pipes
1. Spawn
runtime-process creates a detached pty-host per session with windowsHide: true.
2. Own ConPTY
The pty-host owns node-pty and ConPTY, preserving scrollback and terminal status.
3. Relay
Clients connect over \\.\pipe\ao-pty-<sessionId> using framed binary messages.
| Capability | Before | After | Implication |
|---|---|---|---|
| Terminal durability | Unix durability came from tmux. Native Windows had no equivalent daemon. | Detached pty-host mirrors the tmux-daemon role for Windows sessions. | Agent terminal survives parent/server restarts more predictably. |
| Input/output | Dashboard terminal paths expected tmux attach semantics. | Pipe protocol sends data, input, resize, output request, status, and kill frames. | The browser terminal works without tmux or WSL. |
| Shutdown | Force-killing during ConPTY startup could leave helper processes and error dialogs. | Cooperative MSG_KILL_REQ, 500ms poll, then killProcessTree() fallback. | ao stop can clean detached hosts safely. |
3. Dashboard Terminal
The web UI still speaks the same mux protocol externally, but the server swaps tmux PTY management for a Windows named-pipe relay.
Terminal manager assumed tmux
TerminalManagerattached to tmux sessions throughnode-pty.- Session lookup was tmux-name oriented.
- Windows direct terminal behavior was limited by the lack of native tmux.
Mux relays to Windows pipes
handleWindowsPipeMessage()maps(projectId, sessionId)to a pipe socket.resolvePipePath(sessionId, projectId)reads session metadata to find the pty-host pipe.- Outbound terminal frames echo
projectIdso project pages route xterm output correctly.
4. CLI Commands
The CLI changes are practical Windows work: startup defaults, stop cleanup, PowerShell scripts, and ao open no longer depending on tmux list-sessions.
| Command | Before | After | Why it matters |
|---|---|---|---|
ao start | Unix dashboard process-group behavior leaked into Windows assumptions. | Uses platform-aware runtime fallback and avoids detached dashboard child on Windows. | Ctrl+C reaches the console group naturally on Windows. |
ao stop | Parent process teardown could miss detached Windows pty-hosts. | Calls sweepWindowsPtyHosts() and then process-tree kill. | Stops ConPTY helpers that taskkill /T on the parent cannot see. |
ao doctor / ao update | Shell script flow was Unix-oriented. | Ships ao-doctor.ps1 and ao-update.ps1. | Windows users get native setup and update checks. |
ao open | Session discovery depended on tmux sessions. | Reads sm.list(); Windows opens Terminal/cmd attach or dashboard fallback. | Process-runtime sessions appear and can be opened on Windows. |
5. Agent Plugin Compatibility
The Windows port is only real if agents launch, detect, and update metadata correctly. This PR touched Claude Code, Codex, Aider, OpenCode, Kimicode, Cursor, worktree/clone, and desktop notifier paths.
PATH wrappers
setupPathWrapperWorkspace() generates .cjs + .cmd wrappers for gh/git interception on Windows.
PATHEXT detection
Agent detect() calls use shell: isWindows() so npm .cmd shims resolve.
PowerShell launch
Quoted absolute binaries are called with PowerShell's & operator where needed.
Metadata hooks
Claude/Codex metadata update paths understand Windows-safe Node wrappers and V2 .json metadata.
Drive slugs
Claude Code preserves Windows drive-letter slug encoding for session lookup.
Notifier
Desktop notifications gain Windows toast support while network notifiers remain available.
6. Filesystem, Shell, and Path Safety
Most Windows bugs in this PR were not glamorous: path case, junctions, file-handle races, PATHEXT, PowerShell, and process liveness edge cases.
pathsEqual()resolves real paths and lowercases compare keys on Windows.canonicalCompareKey()creates stable Map/Set keys for paths.- Worktree removal retries
rmSyncaround Windows file-handle drain races. - Symlink fallback uses Windows-friendly junctions/hardlinks where appropriate.
- PowerShell is resolved by absolute path if PATH is degraded.
- Git Bash auto-detection walks PATH and avoids WSL bash for Windows cwd flows.
windowsHide: truesuppresses console flashes for background subprocesses.EPERMis treated as alive during Windows liveness probes;ESRCHmeans gone.
7. Documentation and CI
The final commits turn the port into a maintainable contract: documentation says what to do, CI proves both OS lanes still work.
docs/CROSS_PLATFORM.mdadds the golden rule: useisWindows(), never new inlineprocess.platform === "win32".docs/ARCHITECTURE.mddocuments pty-hosts, pipe protocol, registry, sweep, and mux WS Windows branching.website/content/docs/platforms.mdxreflects Windows process runtime and dashboard terminal support.
- Typecheck runs on
ubuntu-latestandwindows-latest. - Core/package tests run on Linux and Windows.
- Web tests run on Linux and Windows; Linux installs tmux, Windows covers named-pipe mux relay tests.
- CI permissions are reduced to
contents: read.
Implementation Readout
The PR landed as several tight systems. The chronology included merges and QA passes; the final architecture is clean.
Platform adapter
packages/core/src/platform.ts owns OS branching: runtime defaults, shell resolution, process-tree kill, port PID lookup, and env defaults.
Pipe protocol
pty-host.ts and pty-client.ts define framed messages for terminal data, input, resize, status, scrollback, and cooperative kill.
PTY registry
windows-pty-hosts.json lets ao stop find detached ConPTY hosts that parent-process teardown cannot reach.
Agent wrappers
setupPathWrapperWorkspace creates Windows .cjs and .cmd shims for gh and git interception.
CLI scripts
ao-doctor.ps1, ao-update.ps1, Git Bash detection, and PowerShell -File handling make repo scripts usable on Windows.
Open command
ao open now reads sessions from sm.list() and launches Windows Terminal/cmd attach or dashboard fallback.
Commit Story
All 120 commits are grouped below so the presentation can show the narrative without repeating the same Windows claim.
LOC Explanation
The numbers tell the shape of the work: runtime/process code, CLI hardening, agent plugin compatibility, docs, and test coverage.
How To Start AO On Windows
This is the manual runbook validated during the May 5 Windows PR test: first the intended clean path, then the exact field notes from this machine.
Run these in order for your own repo
From your project root, create or replace agent-orchestrator.yaml with the flat PR #1025 format below. Replace OWNER/REPO, main, and the default agent only if your project needs different values. Do not put projects: in this local file.
PowerShell one-shot if you want to write the file from terminal:
Then run the install, build, doctor, and startup flow. On this Windows machine we use corepack pnpm so the repo's pinned pnpm version runs instead of the older global pnpm on PATH.
When AO starts, use the exact dashboard URL printed in the terminal. On Windows the healthy signal includes named-pipe PTY logs and Lifecycle: supervised.
Use the PR's flat local config and process runtime
In PR #1025, the local agent-orchestrator.yaml is behavior config only. The global registry at ~/.agent-orchestrator/config.yaml owns projects:, project IDs, paths, repo metadata, and registration. If the local file has a wrapped projects: map, the dashboard can show a degraded project warning.
Run AO through the repo package manager. On a clean Windows setup with Corepack active and pnpm 9 on PATH, this is the normal flow:
Expected startup signal: Windows mode - using named pipe relay to PTY hosts, WebSocket server listening, Orchestrator session ready, and Startup complete.
The repo wants pnpm 9.15.4; this machine had global pnpm 8.15.5
The root package.json declares packageManager: pnpm@9.15.4. The first install used global pnpm 8.15.5, which treated the lockfile as incompatible and rewrote pnpm-lock.yaml to an older lockfile format. That lockfile change must not be committed.
corepack enable failed with EPERM because it tried to write shims under C:\Program Files\nodejs. But corepack pnpm still worked and ran pnpm 9.15.4 directly, so the test used:
Avoid corepack ao start; that is invalid Corepack syntax. Use corepack pnpm ao start.
Field notes from the Windows smoke run
| Step | Observed | Meaning |
|---|---|---|
| Doctor | tmux not installed passed because Windows default runtime is process. | Confirms the PR does not require native tmux on Windows. |
| Local config | A wrapped projects: file caused the dashboard to show degraded project state. | Use flat local config; the global registry owns project identity. |
| Start | Direct terminal logged named-pipe relay mode, Next.js became ready, and startup completed. | ConPTY/pipe dashboard path is alive on Windows. |
| Stale worktrees | Old ao-166...ao-170 and ao-orchestrator worktrees blocked checkout. | Environment residue from earlier AO sessions; remove with git worktree remove --force and git worktree prune. |
| Windows file handles | git worktree remove repeatedly failed until prune cleared the broken registration. | Windows file-handle cleanup is a real manual-testing hazard; stop AO/dashboard first. |
| Node 24 | better-sqlite3 native bindings were missing, so activity-events DB and FTS tests failed. | Not blocking ConPTY smoke testing, but retest on Node 20 because CI uses Node 20. |
Clean stale AO state without changing source code
Inspect stale Git worktrees:
Remove a stale worktree that blocks checkout:
Stop AO and verify process-runtime cleanup:
If the dashboard still shows an old hash project, open the startup URL printed by ao start, for example /projects/agent-orchestrator_1438835b40/sessions/ao-orchestrator.
After startup, test the runtime surface
Also test from Git Bash after PowerShell passes. The important checks are: no tmux error, terminal is not blank, pipe reconnect works after dashboard refresh, long prompt input is not truncated, and ao stop leaves no stale pty-host registry entries.
Source Trail
This site is based on current branch commits plus the files below. No PPT, blog draft, PDF, DOCX, or existing deck was found in the repo.
docs/CROSS_PLATFORM.md
Developer rules, helper inventory, EPERM handling, shell/path/network checklist.
docs/ARCHITECTURE.md
Windows runtime architecture: pty-host, pipe protocol, mux relay, registry, sweep.
platforms.mdx
Platform-facing docs: Windows uses process runtime, dashboard terminal, supported CLI flows.
native-windows-support.md
Changeset release note for native Windows support and cross-platform ao open.