Phase 6: Native process runtime
Implemented
- Added a typed process manifest with shell-free argv, contained working directories, project/process environment overlays, keychain references, stop timeouts, and bounded opt-in restart policy.
- Added deterministic adoption of reviewed
.switchyard/project.ymlfiles so explicit uv/npm process projects can complete the normal add/trust flow. - Added dependency validation and deterministic topological start/reverse-stop ordering for multi-process projects.
- Added macOS/Linux process groups, separate inherited stdout/stderr pipes, graceful tree termination, forced escalation, start cancellation rollback, and parent-orphan reconciliation.
- Added durable
runsandrun_processesrecords with PID, process-group ID, executable, OS start time, cwd, run ID, restart count, outcome, and SHA-256 identity fingerprint. - Added exact fingerprint reconciliation across daemon restarts and a bounded npm-style launcher handoff window that never treats PID alone as ownership.
- Added non-zero exit reporting and explicit
on-failureretry supervision. - Added live process CPU/RSS metrics, bounded stdout/stderr logs, change-driven runtime events, and external TCP-listener classification using process and ancestor command metadata.
- Extended the generated manifest schema, OpenAPI Go/TypeScript clients, runtime HTTP contract, and CLI rendering for process observations.
Files and modules added
internal/runtime/processinternal/platform/sqlite/runs.gomigrations/00004_native_process_runs.sqltest/fixtures/uv-single-processtest/fixtures/node-single-processtest/integration/native_process_runtime_test.gotest/integration/native_external_unix_test.godocs/architecture/native-process-runtime.md
Architecture decisions
No new ADR was required. The implementation realizes accepted ADR-0007. Run intent and identity evidence are durable; current process state remains a live derived observation. The driver owns platform APIs and credential lookup while runtime domain/application packages remain OS- and persistence-neutral.
The current supported process-inspection dependency is
github.com/shirou/gopsutil/v4 v4.26.5. Process groups are the Phase 6
macOS/Linux authority. Windows Job Objects remain Phase 18 work, consistent
with ADR-0015.
Tests added
- Process manifest shell, secret-reference, binding, and dependency-cycle validation.
- Explicit portable-manifest discovery and accepted-proposal selection.
- Deterministic dependency plans and environment/keychain overlay precedence.
- SQLite run, member-fingerprint, restart-count, and terminal-outcome roundtrip.
- PID reuse rejection and exact external-listener classification.
- Real process-group tree stop, stdout/stderr capture, metrics, parent orphan, crash/exit code, opt-in restart, SIGTERM refusal/escalation, and cancellation rollback tests.
- Real uv and npm fixture onboarding/lifecycle tests with post-stop PID checks.
- Real externally launched uv listener recognition without ownership.
Commands run and results
go test ./internal/runtime/process -count=1PASS: tree, orphan, crash, restart, escalation, cancellation, PID reuse
go test -tags=integration ./test/integration \ -run 'TestUVAndNPM|TestNativeRuntimeRecognizesExternal' -count=1 -vPASS: uv/npm lifecycle and external uv recognition in 4.924 seconds
SWITCHYARD_DOCKER_INTEGRATION=1 go test -tags=integration ./test/integration \ -run TestComposeRuntimeLifecycleObservationLogsMetricsAndExternalRecognition \ -count=1 -vPASS: Compose regression lifecycle and cleanup in 22.39 seconds
make qualityPASS: generated drift, formatting, vet, golangci-lint, architecture checks,frontend lint/typecheck/tests, all Go tests and race tests, migration smoke,govulncheck, Playwright E2E/visual tests, production web build, packaged binary
GOOS=linux GOARCH=amd64 go build -trimpath -o /tmp/switchyard-phase6-linux-amd64 ./cmd/switchyardGOOS=windows GOARCH=amd64 go build -trimpath -o /tmp/switchyard-phase6-windows-amd64.exe ./cmd/switchyardPASS: Linux and Windows amd64 cross-buildsPackaged verification used a fresh SQLite database, private Unix socket, and
loopback address. The built binary completed add, trust, plan, durable start,
running status, stdout/stderr logs, metrics, daemon shutdown/restart, recovered
running status/metrics, durable stop, and final resource checks for the npm
fixture. A first run exposed an event/launcher handoff race; after the bounded
fingerprint-only reconciliation fix, the full flow succeeded. The final ledger
had zero active runs, one stopped outcome, and no TCP listener.
Acceptance criteria status
- The uv and npm fixtures start, report status, stream bounded logs, expose metrics, and stop without orphaned child PIDs.
- A failed process reports its exact exit code and
failedproject state. - A stale/reused PID fails fingerprint verification, becomes
identity_lost, and is never signalled as the original run. - Known shell executables and shell syntax in the executable field are
rejected unless
shell: trueis explicit and previewed. - A matching port/process launched outside Switchyard is reported as
running_externalwith no run ID or ownership claim.
Known limitations
- Captured log buffers are current-daemon memory only. Persistent rotating, redacted log segments and post-restart history are Phase 7.
- Linux keychain lookup requires
secret-tooland a working Secret Service. Windows credential resolution is not yet available. - External recognition requires a declared TCP port plus matching executable or bounded ancestor command evidence. Services without that evidence remain stopped/unknown rather than being guessed.
- Windows currently has a compile-safe single-process termination fallback; Job Object tree ownership is Phase 18.
- Per-process network byte attribution is unavailable and is reported as zero.
Deferred work
- Health scheduling, persistent/redacted logs, retention, and log follow over WebSocket are Phase 7.
- Port reservation/conflict intelligence and process-listener registry are Phase 8.
- Interactive PTY terminals are Phase 14.
Manual verification
make buildswitchyard add test/fixtures/uv-single-processswitchyard project trust uv-single-process --yesswitchyard plan start uv-single-processswitchyard start uv-single-processswitchyard status uv-single-processswitchyard logs uv-single-process --service web --tail 50switchyard metrics uv-single-process --service webswitchyard stop uv-single-process