Skip to content

Native process runtime

Phase 6 implements accepted ADR-0007 behind the driver-neutral runtime application boundary. The process driver owns command construction, supervision, identity reconciliation, output capture, metrics, and external listener classification. HTTP, CLI, catalog, and operation handlers do not call operating-system process APIs.

Manifest contract

A process project declares reusable process definitions and maps each product service to one definition:

runtime:
driver: process
process:
environment:
PORT: "18082"
secrets:
API_TOKEN:
provider: keychain
key: example-api-token
account: developer@example.com
processes:
- id: api
command: [uv, run, fastapi, dev, app/main.py, --port, "18082"]
workingDirectory: .
stopTimeoutSeconds: 10
restart:
mode: on-failure
maxRetries: 2
backoffSeconds: 1
services:
- id: api
source: {process: api}

Project environment is overlaid on the daemon environment, then the process overlay wins. A secret reference wins over a plain value at the same layer and is resolved only at launch. Secret values are never included in plans, manifests, run records, or process metadata. macOS uses the login Keychain via security; Linux uses Secret Service via secret-tool.

Argument arrays execute without a shell. Known shell executables, whitespace in the executable field, and shell-control syntax in that field are rejected unless shell: true is present. Explicit shell mode accepts exactly one script string, is visible in the lifecycle preview, and uses the platform shell. Working directories must remain inside the trusted project root.

Ownership and persistence

Every managed launch creates a runs row and at least one run_processes row. The fingerprint is a SHA-256 digest of canonical executable path, operating system process start time, and canonical working directory. The persisted record also includes PID, process-group ID, run ID, observation time, origin, restart count, exit code, and termination reason.

A PID is never sufficient evidence. Inspection and stop operations re-read the live executable, start time, working directory, and process group and require the exact stored fingerprint. A reused PID becomes stale/identity_lost and is never signalled. A bounded two-second launch-handoff window prevents a fast launcher such as npm from being declared stale while its child fingerprint is being recorded; ownership still requires an exact fingerprint before the service becomes running.

Child members of the OS process group are discovered continuously and stored. If the original parent exits, a verified child keeps the run active. This lets a restarted Switchyard daemon reconcile, measure, and stop a process tree that survived the previous daemon without claiming unrelated processes.

Lifecycle and restart

Dependency ordering is topological and deterministic. Start walks dependencies first; stop walks the reverse order. Cancellation of a multi-service start rolls back every process started by that operation.

Stop sends graceful termination to the verified process group and waits for the manifest timeout. Remaining members receive forced termination and the run records a _forced reason. Restart is stop followed by start. Pause, unpause, rebuild, teardown, and volume flags are rejected for process runtimes.

Crash restart is disabled by default. on-failure restarts only non-zero exits, uses the declared bounded retry count/backoff, records every new fingerprint, and reports the retry count. Exhausted or failed restarts preserve the original exit code and a useful terminal reason.

Observation, logs, metrics, and external processes

Stdout and stderr use separate inherited pipes so child output retains its stream identity even after the launcher exits. Each bounded log entry includes project, service, process definition, run, source, level, and timestamp. Live metrics include CPU, resident memory, and host memory capacity for a verified member. Per-process network byte attribution is not claimed.

An unmanaged listener is reported as running_external only when a declared TCP port maps to a live PID and the declared executable matches that process or one of its bounded ancestors/arguments. Switchyard exposes the observation but does not create a run ID, stream its logs, or stop it. Missing permissions or insufficient evidence produce unknown or stopped, never managed ownership.

Platform boundary

macOS and Linux create and signal real process groups. Windows builds retain a bounded single-process fallback; Job Object ownership, tree termination, and full Windows acceptance coverage remain part of Phase 18 cross-platform hardening. Interactive PTYs remain Phase 14 work.

Use this pageLast verified Jul 17, 2026
Copy-ready MarkdownOpen sourceReport a docs issue