Platform compatibility
This page is the per-capability compatibility table for the Harn runtime. It is the authoritative source on what Harn supports, what it restricts, and what it deliberately defers per host operating system. Integrators packaging Harn binaries should read this top to bottom before promising a feature.
The table is exercised on every release-relevant PR by the
release smoke matrix
(scripts/release_smoke.sh). A regression on any row surfaces as a
::error::release-smoke (<platform>): <capability> failed annotation
that points at the specific (platform, capability) pair, not just
"smoke matrix failed".
Capability matrix
| Capability | macOS | Linux | Windows | Notes |
|---|---|---|---|---|
harn --help, harn --version | Yes | Yes | Yes | Argument parsing, banner emission. Smoke step 1–2. |
harn check (type-check) | Yes | Yes | Yes | Lexer/parser/type checker is platform-independent. Smoke step 3. |
harn fmt --check | Yes | Yes | Yes | LF-only fixtures keep the formatter byte-stable across platforms. Smoke step 4. |
harn package check | Yes | Yes | Yes | Manifest parsing, exports resolution, path normalization. Smoke step 5. |
Generated artifacts (harn providers matrix) | Yes | Yes | Yes | Deterministic-text emitter; line endings, sort order, and rounding are normalized in the writer. Smoke step 6. |
harn run | Yes | Yes | Yes | VM bootstrapping + stdlib startup. Smoke step 7. |
Process spawning (std/command::command_run) | Yes (sandbox-exec / Seatbelt) | Yes (Landlock + seccomp; falls back to warn under HARN_HANDLER_SANDBOX=warn) | Yes (AppContainer + Job Objects; warn fallback applies the same way) | Sandbox backend differences are encapsulated in crates/harn-vm/src/stdlib/sandbox/ (one file per OS) behind a shared SandboxBackend trait. Scripts pick argv via platform(). Smoke step 8. |
No-credentials workflow (provider: "mock") | Yes | Yes | Yes | Drives llm_call end-to-end through the in-memory mock provider with no API keys, network, or platform secret store. Smoke step 9. |
File watching (harn watch) | Yes (FSEvents) | Yes (inotify) | Yes (ReadDirectoryChangesW) | All three backends provided by the notify crate. Smoke step 10 boots the watcher and verifies the readiness banner; graceful shutdown via SIGTERM is Unix-only (see below). |
Graceful orchestrator shutdown (SIGTERM drain) | Yes | Yes | Deferred | Tests that depend on the orchestrator drain are gated #![cfg(unix)]. See Windows test coverage for the inventory. On Windows the smoke kills harn watch with taskkill /F. |
unveil(2) / pledge(2) host confinement | n/a | n/a | n/a | Implemented for OpenBSD only; not surfaced in the release smoke matrix because OpenBSD is not a published target. |
Behavior differences by category
Path handling
- All Harn fixtures and configuration files are stored with LF line
endings. This is enforced by
.gitattributesfor thetests/smoke/tree,docs/src/provider-matrix.md,docs/src/connectors/parity-matrix.md, and other generated artifacts that are byte-compared in CI. - Path separators in user-facing scripts use
/. The runtime canonicalizes paths throughstd::path::Pathbefore sandbox-policy enforcement, so a script written on macOS with/-separated paths runs unchanged on Windows. - Windows-only path normalization quirks (UNC, extended-length, drive
letters) are absorbed by
crates/harn-vm/src/stdlib/sandbox/windows.rsbefore policy enforcement.
Line endings
- The release smoke matrix builds and runs with
core.autocrlf=falseby virtue of.gitattributeseol=lfdirectives. harn fmtpreserves whatever line endings the input file has; release smoke fixtures pin LF so the formatter never churns on a Windows checkout.- The provider matrix emitter (
harn providers matrix) writes LF on every platform. CI verifies byte-identical output across the matrix as smoke step 6.
Process spawning and sandboxing
-
Per-platform sandbox backends live in
crates/harn-vm/src/stdlib/sandbox/(one file per OS) behind a sharedSandboxBackendtrait. The default profile isworktree(workspace-root path enforcement plus best-effort OS confinement). Pipelines opt intosandbox_profile: "os_hardened"via the activeCapabilityPolicyto make OS confinement required — see Process sandboxing. The fallback mode iswarn, configurable viaHARN_HANDLER_SANDBOXfor theworktreeprofile only;os_hardenedalways enforces. -
Scripts must pick platform-appropriate argv when shelling out. The canonical pattern (used by smoke step 8) is:
fn echo_argv(text) { if platform() == "windows" { return ["cmd", "/C", "echo " + text] } return ["printf", "%s", text] } -
The release smoke does not assert that the sandbox enforced a specific syscall mask. That belongs in unit tests on the matching platform; the smoke matrix only confirms each backend resolves and spawns successfully.
Signals
SIGTERM/SIGINT-driven shutdown drains apply to Unix only. The orchestrator andharn watchrely ontokio::signal::unixfor the drain path; on Windows the equivalent is forceful termination viaTerminateProcess(which the smoke driver invokes throughtaskkill /F).- Any new orchestrator or daemon test that depends on a clean drain must add a row to Windows test coverage.
File watching
- All three notify backends (FSEvents on macOS, inotify on Linux,
ReadDirectoryChangesW on Windows) are exercised via
harn watchin smoke step 10. The smoke does not assert that a re-run fires; it asserts that the watcher reaches its readiness banner. Re-run logic is covered by per-backend integration tests incrates/harn-cli.
Adding a new capability
When you add a new user-visible capability (CLI subcommand, stdlib builtin, or sandbox-touching surface):
- Add a row to the matrix above, even if every cell is "Yes". The row is the smoke driver's contract.
- If the capability needs to be exercised at release time, add a step
to
scripts/release_smoke.shkeyed offplatform()(in Harn) or thePLATFORMshell variable (in the driver). - If the Windows path is genuinely deferred (e.g. POSIX-signal drain), document why in this page and add a row to Windows test coverage. The two pages cross-reference; do not let them drift.
- Add the new fixture under
tests/smoke/and verify locally viamake release-smoke.