--- title: internal/multiplexer description: Go API reference for the multiplexer package. --- # multiplexer ```go import "github.com/jbcom/radioactive-ralph/internal/multiplexer" ``` Package multiplexer detaches the Ralph supervisor from the calling shell so \`radioactive\_ralph run \-\-detach\` returns control to the operator while the supervisor keeps running. Three backends are probed in order, from strongest to weakest: 1. tmux — if $TMUX is set or \`tmux\` is on PATH. Operator can later re\-attach with \`tmux attach \-t \\` to see the live supervisor output. This is the recommended backend on every platform that has it. 2. screen — fallback if tmux is unavailable. Less featureful UI but same attach/detach model. 3. setsid \+ double\-fork — pure\-stdlib fallback via syscalls. Runs the supervisor as an orphaned process inherited by init \(pid 1\) with stdin/stdout/stderr redirected to a log file. No re\-attach is possible in this mode — operators use \`radioactive\_ralph attach\` \(Unix socket\) or tail the log directly. Service\-installed variants \(brew services, launchd, systemd \-\-user\) always invoke the supervisor in \-\-foreground mode, bypassing this package entirely. The service manager itself is the supervisor's parent. ## Index - [Variables](<#variables>) - [type Backend](<#Backend>) - [func \(b Backend\) String\(\) string](<#Backend.String>) - [type Detacher](<#Detacher>) - [func Detect\(opts ...DetectOption\) \(\*Detacher, error\)](<#Detect>) - [func \(d \*Detacher\) Backend\(\) Backend](<#Detacher.Backend>) - [func \(d \*Detacher\) SpawnDetached\(req SpawnRequest\) \(Spawned, error\)](<#Detacher.SpawnDetached>) - [type DetectOption](<#DetectOption>) - [func WithGetenv\(fn func\(string\) string\) DetectOption](<#WithGetenv>) - [func WithLookPath\(fn func\(string\) \(string, error\)\) DetectOption](<#WithLookPath>) - [func WithPreferredBackend\(b Backend\) DetectOption](<#WithPreferredBackend>) - [type SpawnRequest](<#SpawnRequest>) - [type Spawned](<#Spawned>) ## Variables ErrNoBackend is returned if Detect cannot find a usable backend. On current macOS/Linux this essentially never happens because the setsid fallback always succeeds. ```go var ErrNoBackend = errors.New("multiplexer: no backend available (no tmux, no screen, no setsid)") ``` ## type [Backend]() Backend identifies which detach mechanism a Detacher will use. ```go type Backend int ``` ```go const ( // BackendUnknown is the zero value; only returned by Detect when // an explicit override asked for an unknown kind. BackendUnknown Backend = iota // BackendTmux uses `tmux new-session -d` for full detach with later re-attach. BackendTmux // BackendScreen uses `screen -dmS` for detach with later re-attach. BackendScreen // BackendSetsid uses syscall.Setsid + double-fork for pure-POSIX detach // with no re-attach UI (operator uses `radioactive_ralph attach` or tails the log). BackendSetsid ) ``` ### func \(Backend\) [String]() ```go func (b Backend) String() string ``` String returns a human\-friendly backend name. ## type [Detacher]() Detacher encapsulates one chosen backend and knows how to spawn the supervisor command detached from the calling shell. ```go type Detacher struct { // contains filtered or unexported fields } ``` ### func [Detect]() ```go func Detect(opts ...DetectOption) (*Detacher, error) ``` Detect probes the environment and returns a Detacher bound to the strongest available backend. ### func \(\*Detacher\) [Backend]() ```go func (d *Detacher) Backend() Backend ``` Backend reports which detach mechanism this Detacher is bound to. ### func \(\*Detacher\) [SpawnDetached]() ```go func (d *Detacher) SpawnDetached(req SpawnRequest) (Spawned, error) ``` SpawnDetached spawns req fully detached using the Detacher's chosen backend. See the package\-level comment for the precedence order. ## type [DetectOption]() DetectOption customises Detect. These compose for tests where we need to force a specific backend or swap out the probe. ```go type DetectOption func(*Detacher) ``` ### func [WithGetenv]() ```go func WithGetenv(fn func(string) string) DetectOption ``` WithGetenv overrides os.Getenv. Used by tests to toggle $TMUX. ### func [WithLookPath]() ```go func WithLookPath(fn func(string) (string, error)) DetectOption ``` WithLookPath overrides exec.LookPath. Tests pass a stub that reports specific binaries as missing to exercise each fallback branch. ### func [WithPreferredBackend]() ```go func WithPreferredBackend(b Backend) DetectOption ``` WithPreferredBackend forces a specific backend if available; Detect will return ErrNoBackend if the preferred one probes as missing. Used by \`radioactive\_ralph run \-\-multiplexer X\` CLI flag and by init wizard when the operator has explicitly chosen a backend. ## type [SpawnRequest]() SpawnRequest describes a process the supervisor wants spawned detached. All file paths must be absolute; SpawnDetached does no path resolution. ```go type SpawnRequest struct { // Name is the command to exec. Usually the absolute path to // radioactive_ralph itself, e.g. "/usr/local/bin/radioactive_ralph". Name string // Args are passed to Name. Typically something like // ["_supervisor", "--variant", "green", "--repo-root", "..."]. Args []string // SessionName is the human identifier (tmux session name, screen // session name, or a tag written into the log file header for setsid // mode). Should be unique per per-variant supervisor on this host; // the supervisor package generates it as // `radioactive_ralph--`. SessionName string // LogPath receives stdout + stderr of the spawned supervisor (setsid // mode uses it as the primary record; tmux/screen sessions also // `pipe-pane` / `logfile` to it for `radioactive_ralph attach` fallback tailing). LogPath string // Env is passed through to the detached process. Nil means inherit // the current environment. Env []string // Dir sets the working directory of the detached process. Supervisor // is typically spawned with Dir = operator's repo root. Dir string } ``` ## type [Spawned]() Spawned is the return value of SpawnDetached. Descriptor names how to re\-reach the detached process \(tmux/screen session name\), and PID carries the child PID for backends that know it synchronously. SpawnDetached itself runs req.Name with req.Args fully detached. For tmux/screen it blocks only long enough to invoke the multiplexer's own detach command \(\~millisecond\). For setsid it performs a double\-fork and returns when the grandchild has execve'd. ```go type Spawned struct { // Descriptor names how to re-reach the detached process. For tmux: // the session name passed to `tmux attach -t `. For screen: // the session name passed to `screen -r `. For setsid: the // empty string (no re-attach available; use `radioactive_ralph attach` socket). Descriptor string // PID is the process ID of the detached supervisor if the backend // knows it immediately. tmux/screen may not populate this // synchronously — call ralph status or read the PID file written by // the supervisor itself. PID int } ``` Generated by [gomarkdoc]()