Expand description
Run child processes in their own systemd scope (Linux).
systemd-oomd, under memory pressure, kills a whole cgroup at once, choosing the one using the most swap. Without this, everything Synaps starts lives in the cgroup of whatever started Synaps — usually a terminal’s scope. A single runaway tool command (S348: a 270-file test run from the bash tool) then makes that whole scope the biggest, and systemd-oomd kills it: the command, the daemon, every session it hosts, and the terminal.
A scope gives each child a separate cgroup, not a memory cap. An ancestor cgroup OOM or global kernel OOM can still kill the daemon and other scopes. Windows isolation is not implemented.
systemd-run --user --scope registers a transient scope for its own pid
and then execs the command in place: same pid, process group, session,
environment, inherited fds and stdio. Group cleanup covers descendants that
remain in that group. Each launch first performs a bounded fresh probe.
Command arguments are passed verbatim: where systemd-run supports it
(systemd >= 254, from a cached --version), --expand-environment=no
stops it from substituting ${NAME} in tool scripts before exec.
Used only when it is available (Linux, a reachable systemd user manager)
and not turned off (process_scopes = off in config, or
SYNAPS_PROCESS_SCOPES=off). Otherwise commands start exactly as before.
Slices: by default systemd puts each scope where the user manager puts
transient units (usually app.slice, next to the desktop’s apps). The
config keys tool_scope_slice (bash tool commands and PTY shells) and
daemon_scope_slice (the daemon’s own scope) pass --slice=<name>, so
an operator can cap agent tool work on its own slice. Synaps sets no
limits; the operator sets them on the slice. The probe uses the same
--slice: when it fails (no reachable user manager, or a slice it
refuses) the command starts as it does without scopes, with one WARN per
slice name. A slice that doesn’t exist is not refused: systemd creates it
on the fly, without limits. So, once per slice name and on a background
thread, Synaps asks the manager for the slice’s limits and WARNs if none
is set (a typo, or a unit file not yet daemon-reloaded).
Structs§
- Scope
Launcher - Turns
program args…intosystemd-run --user --scope … -- program args….
Enums§
- Scope
Kind - Which of Synaps’s scopes a launch makes. Each kind has its own slice key.
Functions§
- inherited_
env - Snapshot inherited environment before applying child-specific overrides.
- launcher_
for_ effective_ env - Fresh, bounded availability check. Synchronous callers (PTY and detached
daemon spawn) may wait up to three seconds. Async callers must offload it.
Probe failure selects direct launch. After success, wrapper failure is an
error, NEVER a reason to replay the command: availability can race, and the
wrapped command may already have executed. This is not a launch handshake.
kindpicks the slice key (tool_scope_slice/daemon_scope_slice), read from the config this call loads. - launcher_
for_ env - Compatibility convenience for inherited or fully rebuilt environments, for a tool launch.
- resolve_
program - Resolve before wrapping: systemd-run must not substitute its own executable search rules for the child’s PATH/cwd. Missing programs remain spawn errors.
- set_env