Documentation / guides
Process Supervision
Compose long-running Bash commands with the shared Tools process supervisor.
The process package is the Tools-owned runtime for long-running commands. It owns opaque process identity, state transitions, bounded output, process quotas, manifests, restore reconciliation, and the three follow-up tools. It is runner-free: the product composition root supplies the tool.AsyncProcessRunner to BashDefinition, while the supervisor owns the admitted process after PrepareProcess and the workspace lease are handed to Start.
One Session Resource
Supervised Bash and the process companion definitions use the same process.SupervisorResourceKey:
BashDefinitionresolves the async runner with the validatedbindings.LoopIDand builds the supervised Bash tool.ProcessOutputDefinition,ProcessInputDefinition, andProcessStopDefinitionresolve the same session resource frombindings.Process.Registry.process.NewSupervisorResourcecreates one runner-free supervisor and its manifest store.SupervisorResource.Activatelate-binds Harness lifecycle and completion services, then restores persisted manifests before calls are used.
The registry is keyed per session. Definitions built against the same registry share the supervisor. Different session registries produce different supervisors. The companion tools require process services but do not require a workspace binding.
Identity Is Authority
Every admitted process has an immutable process.Identity:
Handleis URL-safe random data with 128 bits of entropy. It contains no PID, path, timestamp, or owner data.Owneris the exactSessionIDandLoopIDallowed to inspect, write to, or stop the process.Originstores the creating Bash execution ID for audit only. Follow-up calls have their own execution IDs and authorize throughOwner, neverOrigin.
A missing handle and a handle owned by another session or loop are deliberately indistinguishable. ProcessOutput, ProcessInput, and ProcessStop report not_found for either case.
%%{init: {"theme":"dark"}}%%
flowchart LR
B[BashDefinition] -->|Build with LoopID| A[AsyncProcessRunner]
A -->|PrepareProcess and lease| S[Supervisor.Start]
S --> H[Opaque Handle plus Owner]
H --> O[ProcessOutput]
H --> I[ProcessInput]
H --> P[ProcessStop]
S --> M[Manifest and bounded spool]
Admission and Quotas
Supervisor.Start rejects shutdown admission, validates a prepared process, reserves loop and session running-process slots, reserves aggregate in-memory and spool ceilings, allocates stable lifecycle and completion IDs, and persists a starting manifest before returning the handle. A failed start releases the reservation, lease, and single-use prepared process.
The zero process.Config is valid and normalizes to bounded defaults: 8 running processes per loop, 32 per session, 1 MiB in-memory retention per process, 64 MiB spool retention per process, a 32 KiB inline result cap, 64 pending waiters, 1 MiB pending input, and a 5 second graceful shutdown period. Explicit negative or inconsistent limits fail with invalid_settings.
Use Process Lifecycle, Storage, and Restore for terminalization and restart behavior, and Process Output, Input, and Stop Tools for the model-facing follow-up calls. Harness’s tool-call lifecycle and Inference’s streaming tool-call deltas carry the surrounding model exchange.
Runnable Example
The process lifecycle fixture uses a controlled tool.Process, starts it through Supervisor.Start, shuts it down, and restores a persisted running manifest as lost_on_restore.
supervisor, err := process.NewSupervisor(
process.Config{GracefulShutdownPeriod: time.Millisecond},
process.NewManifestStore(manifestDir),
spoolDir,
nil,
nil,
)
if err != nil {
panic(err)
}
handle, err := supervisor.Start(ctx, owner, origin, prepared, lease, nil, nil,
process.StorageCeiling{}, process.YieldSettings{})
if err != nil {
panic(err)
}
fmt.Println(handle.Valid())