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

CapabilitymacOSLinuxWindowsNotes
harn --help, harn --versionYesYesYesArgument parsing, banner emission. Smoke step 1–2.
harn check (type-check)YesYesYesLexer/parser/type checker is platform-independent. Smoke step 3.
harn fmt --checkYesYesYesLF-only fixtures keep the formatter byte-stable across platforms. Smoke step 4.
harn package checkYesYesYesManifest parsing, exports resolution, path normalization. Smoke step 5.
Generated artifacts (harn providers matrix)YesYesYesDeterministic-text emitter; line endings, sort order, and rounding are normalized in the writer. Smoke step 6.
harn runYesYesYesVM 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")YesYesYesDrives 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)YesYesDeferredTests 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 confinementn/an/an/aImplemented 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 .gitattributes for the tests/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 through std::path::Path before 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.rs before policy enforcement.

Line endings

  • The release smoke matrix builds and runs with core.autocrlf=false by virtue of .gitattributes eol=lf directives.
  • harn fmt preserves 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 shared SandboxBackend trait. The default profile is worktree (workspace-root path enforcement plus best-effort OS confinement). Pipelines opt into sandbox_profile: "os_hardened" via the active CapabilityPolicy to make OS confinement required — see Process sandboxing. The fallback mode is warn, configurable via HARN_HANDLER_SANDBOX for the worktree profile only; os_hardened always 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 and harn watch rely on tokio::signal::unix for the drain path; on Windows the equivalent is forceful termination via TerminateProcess (which the smoke driver invokes through taskkill /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 watch in 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 in crates/harn-cli.

Adding a new capability

When you add a new user-visible capability (CLI subcommand, stdlib builtin, or sandbox-touching surface):

  1. Add a row to the matrix above, even if every cell is "Yes". The row is the smoke driver's contract.
  2. If the capability needs to be exercised at release time, add a step to scripts/release_smoke.sh keyed off platform() (in Harn) or the PLATFORM shell variable (in the driver).
  3. 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.
  4. Add the new fixture under tests/smoke/ and verify locally via make release-smoke.