Skip to content

[prototype] Windows daemon support via named pipes#146

Draft
maplesyzzurp wants to merge 3 commits into
OpenCoven:mainfrom
maplesyzzurp:feat/windows-daemon-named-pipe
Draft

[prototype] Windows daemon support via named pipes#146
maplesyzzurp wants to merge 3 commits into
OpenCoven:mainfrom
maplesyzzurp:feat/windows-daemon-named-pipe

Conversation

@maplesyzzurp
Copy link
Copy Markdown
Contributor

@maplesyzzurp maplesyzzurp commented May 29, 2026

Stacked on #145. This branch is based on #145 (the loopback Host/Origin guard); the Windows named-pipe work sits on top and the daemon.rs overlap between the two is resolved here, so the two no longer conflict at merge. Please merge #145 first — GitHub will then collapse this PR's diff down to just the Windows delta. (The base can't be retargeted to #145 directly: this is a cross-fork PR and GitHub requires the base branch to live in this repo.)


Draft / proof-of-concept — not a merge request. Opening for visibility + to get a decision on the approach before investing further (and PRs are frozen until July per CONTRIBUTING).

Summary

Today coven daemon is Unix-only (coven daemon serve bails with "only implemented on Unix-like systems for now"; the whole socket/serve path is #[cfg(unix)]). This prototype makes the daemon serve the existing /api/v1/* API on Windows over a named pipe, so coven daemon serve works on Windows. The published @opencoven/cli-windows package is staged, so Windows support is presumably wanted — this is a starting point.

What works (verified)

  • Windows: coven daemon serve binds a named pipe and serves the API; a new #[cfg(windows)] test connects a client and gets HTTP/1.1 200 OK from /api/v1/health. cargo build/clippy clean on Windows.
  • Unix: unchanged — cargo test --workspace --locked green (693 + 4 tests, 0 failed); cargo clippy clean.

Approach

  • Lifted the transport-agnostic HTTP layer (handle_http_stream + the request/header/body readers, already generic over Read/Write) out of #[cfg(unix)] so both transports reuse it.
  • Added a #[cfg(windows)] named-pipe transport using the interprocess crate (windows-only dep). Pipe name is derived from COVEN_HOME (hashed) so each home gets a stable, unique pipe.
  • A few genuinely Unix-only helpers (TCP listener, chat-client HTTP helpers) were gated #[cfg(unix)] to keep the Windows build warning-clean.

Deferred (NOT in this prototype)

  • Windows daemon start/stop/status process management (the Unix path shells out to kill/kill -0).
  • Stream-mode kill (PipedKiller uses setsid + kill(-pid, SIGKILL)); Windows needs a Job Object / TerminateProcess equivalent.

Open question for the maintainer

The new interprocess dependency (windows-only) is the key decision. Acceptable? Or would you prefer raw AF_UNIX (Win10 1803+ supports it) or a different transport abstraction? Happy to adjust — that's why this is a draft.

Closes part of the Windows-support gap; full parity is follow-up work.

maplesyzzurp and others added 3 commits May 30, 2026 03:51
- Add `interprocess = "2"` as a `[target.'cfg(windows)'.dependencies]`
- De-cfg the platform-agnostic HTTP layer (`handle_http_stream`,
  `read_http_request_line`, `read_http_headers`, `read_http_body`,
  `parse_request_line`, `write_payload_too_large`) so Windows reuses it
- Add `windows_pipe_name` (DefaultHasher, no new deps) and
  `#[cfg(windows)] serve_forever` binding a GenericNamespaced named pipe
  via `ListenerOptions` and serving the existing HTTP-over-pipe API
- Wire `DaemonCommand::Serve` in main.rs: unix and windows each call
  `daemon::serve_forever`; other platforms bail with a clear message
- Add `#[cfg(windows)] serves_health_over_windows_named_pipe` test that
  binds a pipe in a thread, connects a client `Stream`, sends a health
  request, and asserts `HTTP/1.1 200 OK` + `"apiVersion"` in the response
- Suppress pre-existing dead-code lint regressions on Windows by gating
  the unix-only TCP helpers, `DaemonHealthStatus`, and related imports
  with `#[cfg(unix)]`; gate corresponding tests the same way

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
conversation.id is forwarded verbatim as the harness CLI's
--session-id/--resume argument. On Windows the harness resolves to a
.cmd shim, so CreateProcessW runs it through cmd.exe, which re-parses the
command line; an id carrying shell metacharacters could inject commands.
Require letters, digits, '-', '_', or '.' — UUIDs and opaque slugs pass,
whitespace and metacharacters do not.
@maplesyzzurp maplesyzzurp force-pushed the feat/windows-daemon-named-pipe branch from 14df03c to 2e2dae6 Compare May 30, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant