Skip to content

Session processes

Inspect and stop background processes and terminals owned by a session, including work left running after it stops.

For people running agent work15 pages in this section

A session can start a development server, watcher, or background command that keeps running after the agent finishes. The composer’s Processes control shows the number of background processes and native terminals, their commands, age, and listening ports. Commands include readable arguments with the standard redaction rules applied, and fall back to the process name when unavailable. Foreground tool commands appear in the list but do not add to the badge count or its summary ports. Select a row to stop that process, or stop all listed processes for the session.

When stopping, archiving, or deleting a session, choose whether to keep its processes or terminate them. Keeping is the default. Canceling a turn and releasing an idle agent do not request process cleanup. Processes left running in the command palette collects processes belonging to stopped, archived, deleted, or unknown sessions across projects and profiles.

Use the CLI

compozy session processes <session-id> -o json
compozy session processes stop <session-id> --pid <pid> --started-at <timestamp> -o json
compozy session processes stop <session-id> --all -o json
compozy session stop <session-id> --terminate-processes -o json
compozy session archive <session-id> --stop --keep-processes -o json
compozy session remove <session-id> --terminate-processes -o json
compozy process list --orphaned --all-workspaces --all-profiles -o json

Copy pid and the exact started_at from the list. A PID alone is insufficient: the operating system can reuse it for a different process. --keep-processes and --terminate-processes are mutually exclusive. Omitting both keeps processes.

HTTP, UDS, and native tools

The session routes are GET /api/workspaces/{workspace_id}/sessions/{session_id}/processes and POST /api/workspaces/{workspace_id}/sessions/{session_id}/processes/terminate. Termination takes exactly one selection: {"all":true} or {"targets":[{"pid":123,"started_at":"<timestamp>"}]}. The native tools compozy__session_processes_list and compozy__session_processes_terminate use the same session ownership checks. Termination is a destructive tool and follows the session’s approval policy.

Stop accepts processes: "keep" | "terminate" in its JSON body alongside wait. Archive and DELETE accept the processes query parameter. Omission means keep on every surface. A failed ownership refresh does not block keeping processes. Explicit termination requires a supported scanner and is rejected before the session transition when inspection is unavailable. Once a stop is accepted or an archive/delete transition succeeds, requested cleanup continues with a bounded execution lifetime even if the client disconnects.

Operators can read GET /api/processes?all_workspaces=true&all_profiles=true&orphaned=true and terminate listed identities with POST /api/processes/terminate and a targets array. This route also works when the original session no longer exists; it does not accept all. Profile and workspace ownership are retained with the observation. Raw process environments are never returned.

A result reports terminated, already_exited, identity_mismatch, failed, or unproven for each target. Treat only the first two as verified completion. Verified group members receive individual PID signals, so a process joining the group after inspection is not included. A successful request can contain an unverified result; inspect every row. The durable audit event is session.processes.terminated. An audit-write failure is reported after attempting the remaining selected targets. A transient initial inspection failure is logged and retried; it does not prevent daemon startup or expose unverified saved observations.

Attribution and restart behavior

On macOS and Linux, CompozyOS uses the inherited COMPOZY_SESSION_ID marker and observes the live agent’s descendants. Rows identify their source as attribution: "env" | "lineage". Exact process identities and ownership observations survive daemon restart, and are rechecked before being shown. Dead identities are pruned. Reused PIDs and process groups do not inherit old ownership.

The scanner shares one snapshot, normally every five seconds while clients or sessions need it. During tool calls it observes the process tree every 250 milliseconds. Environment and port inspection stays on the slower cadence; opening the process list refreshes it immediately. On macOS, listening-port and working-directory enrichment uses a bounded lsof query.

Daemon shutdown preserves detached session descendants. Native terminals retain their existing shutdown behavior and are closed by the terminal manager. PTY survival across restarts is not supported. Keeping processes also does not prevent a process from exiting itself, receiving signals from its parent, or being closed by an existing terminal lifecycle.

macOS restricts environment inspection for protected platform binaries. A protected process that detaches and changes process group before the first ancestry observation cannot be attributed. Apple’s XNU sysctl_procargsx implementation contains this environment restriction. An observed protected process remains attributable after reparenting and restart. Do not disable system protections to make it visible.

An unknown session’s environment marker needs matching daemon-home and profile markers to establish ownership. A legacy process with only a session ID and no retained observation cannot be safely assigned to a deleted session’s profile. Windows reports supported: false and does not show the process control. Explicit lifecycle termination is unavailable there, and CLI process termination exits with an error.

On this page