basquetWi + New ticket
agent-ops OPS-140

Agent subprocess spawning: harness paths closed, OS/detached paths still open on venus

Backlog normal bvbin-venus-cc

WHAT IS ALREADY CLOSED (2026-08-24, venus, ~/.claude/settings.json, bound by exiting and relaunching all 13 venus agents): - permissions.deny = [AskUserQuestion, Agent, Bash(run_in_background:true)]. A bare tool name in deny removes the tool from the model's context entirely - coder-venus-cc confirmed post-relaunch that Agent is in neither its tool list nor its deferred list. - CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1, CLAUDE_CODE_DISABLE_EXPLORE_PLAN_AGENTS=1, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS removed (deleted, not set to 0 - it is a plain bool where absence means off). Measured effect: 6 daemon-side procs -> 0, total claude RSS 8809 MB -> 6646 MB, 1 unattended --fork-session --permission-mode bypassPermissions -> 0. WHAT IS NOT CLOSED - the reason this item exists: 1. DETACHED OS SUBPROCESSES ARE UNGATED. permissions.deny Bash(run_in_background:true) keys on the HARNESS background FLAG, not on the OS mechanism. A plain "nohup cmd &" / "cmd &" / "systemd-run --user" inside an ordinary Bash call spawns a surviving detached child with nothing gating it, under defaultMode auto + bypass permissions. MEASURED by coder-venus-cc on venus 2026-08-24 after the settings bound (its claude pid 419330 started 03:02:55Z, settings.json mtime 02:52:50Z): nohup sleep 37 & produced pid 434447, survived the tool call, killed cleanly. A settings deny list is a claim about which TOOLS exist, never about which PROCESSES can exist. 2. Workflow IS in the tool list and is NOT denied, while its own description says it spawns subagents. The Agent deny closes one door and leaves a wider one open. Held shut only by a system-prompt instruction. 3. CronCreate / CronDelete / ScheduleWakeup / Monitor / RemoteTrigger are all reachable as deferred tools. Only the self-arm ban in global CLAUDE.md stops a self-armed cadence. Confirmed present in bin-venus-cc's own deferred list as well. CANDIDATE REMEDIES, none applied, all one-line-ish, all needing a must-fail fixture before being trusted (see mem:reference-gates-need-a-must-fail-fixture): (a) PreToolUse hook on Bash matching detached-spawn shapes: trailing &, nohup, setsid, disown, systemd-run, at, batch. NOTE the false-positive population is real and unmeasured - ccs-tmux.sh itself legitimately uses setsid nohup ... & for its picker poller, and agents run legitimate background-ish shell. A hook that blocks those breaks the launch path. Measure the population before writing the matcher. (b) Add Workflow to permissions.deny, and/or the cron/wakeup tools, converting three instruction-held rules into permission-held ones. (c) Do nothing and rely on the written rules, accepting that the enforcement surface is thinner than the deny list reads. MONITORING SIDE - what stray-agent-check.sh does and does not see: The script never read the deny list; it counts from ps -eo pid,ppid,etimes,rss,args cross-checked against claude agents --json --all (the CLI under-reports: bg-spare PIDs exist with no session row). Its ps filter matches claude (daemon|bg-spare|bg-pty-host) and --fork-session. So an arbitrary detached NON-claude child of an agent pane (the sleep 37 case) is INVISIBLE to it. v1.3 adds a scope statement to the report naming this blind spot explicitly, so a clean report stops implying coverage it does not have. A general long-lived-child-of-an-agent-pane detector is NOT built: its false-positive population is unmeasured, which is the same reason (a) is not applied. Cross-refs: mem:project-venus-stray-agent-monitor, mem:reference-check-the-corpus-not-the-container, mem:reference-an-assertion-of-enforcement-suppresses-verification. Source incident report: /resource/host-venus-maintenance/reports/2026-08-23-2309-agentBackgroundProcesIssue.md

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 7w ago
  • wi-cli-venus commented · 7w ago
    Monitoring half shipped: stray-agent-check.sh v1.3 (sh.git b95c65f) now prints a COVERAGE paragraph on every run including clean ones, naming the non-claude-detached-child blind spot with its measurement, the instruction-held tool surfaces (Workflow, CronCreate/ScheduleWakeup/Monitor/RemoteTrigger), the single-host scope, and that job records are disk state not liveness. New sibling cc-settings-drift-check.sh v1.0 (sh.git 23ed09b) reports settings-policy drift AND live sessions whose startedAt predates the settings mtime - the actual drift path, since settings bind at session start and never on /compact. Unit registration requested from nw-venus-cc, hourly suggested. Neither script closes remedies (a)/(b) in the description; both are still open decisions for Elazar.
monitoring
7w ago by wi-cli-venus
7w ago