Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

Abandoned helper processes are cleaned up

When an agent's tool call gives up on a long command, the command itself keeps running with nobody waiting for it — and on a busy day dozens of these pile up holding memory and slowing the whole machine. Omniscio now finds those abandoned process trees, reports them first, and ends them once you turn enforcement on.

What it is

When an agent runs a command that takes too long — a test run, a type check, a rebase — the agent's tool call gives up after a few minutes, but the command it started does not stop. The shell that launched it and everything under it (test workers, compilers, git) keep running with nobody waiting for the result, until Omniscio itself exits. On a busy day dozens of these pile up: measured on 2026-09-08, 30 abandoned trees at once, together holding hundreds of processes and gigabytes of memory, which is a big part of why the whole machine feels slow.

Omniscio now finds these trees and, once you turn enforcement on, ends them.

Where to find it

There is no panel. The sweep runs in the background and writes its census to a durable log you read from the command line; enforcement is a setting, so turning it on is a deliberate step rather than a switch in the UI.

How it behaves

How it decides (the conservative filter)

Every two minutes the existing orphan sweep looks at every process and keeps ONLY trees that pass all of these:

  • The launcher is gone — the shell that started the tree has exited (or been replaced by an unrelated process that reused its id).
  • It is a tool-call shape — the root is the npm, npx or git helper an agent's command goes through, or the agent's own shell wrapper. Servers, brokers, watchers and anything you started yourself are never even considered.
  • It is older than 15 minutes — longer than the longest wait an agent's tool call can have, so nothing still being waited on can qualify.
  • The script is a short-lived kind — a test, build, check, rebase, translation, cloud or similar family. A dev server, a watcher, a mock server or any name Omniscio has not seen before is left alone and recorded so the list can grow on evidence.
  • No gate owns it — nothing that belongs to a running cloud check or a registered gate watch.
  • No git work is in flight — no rebase, merge, commit or checkout anywhere in the tree, and no half-finished git operation in the worktree it names.
  • It belongs to a session (enforcement only) — the tree sits inside Omniscio's session Job Object.

Anything that fails one test is skipped with the reason recorded.

Shadow first: read the census before turning it on

Out of the box nothing is ended. The sweep only writes what it WOULD have ended, and why, to a durable log. Read it with:

npm run orphans:status
npm run orphans:status -- --hours=72 --json

It shows the verdict counts, the skip reasons, the shapes and scripts involved, the "shadow duty" (how many trees and processes would have been cleaned up), and warnings when something upstream is off (an empty session Job, an unreadable gate-watch store).

The other half of the same question: shells that ran un-contained

The same report ends with a section headed "Uncontained shells (trampoline)", and it answers the mirror-image question. Every command an agent runs goes through a small wrapper that puts the shell into a job Omniscio can end as a unit — so if the command is killed, everything under it goes with it. That wrapper is deliberately fail-open: if it cannot build that job it runs the command anyway, because refusing to run an agent's command would be worse than the risk. The command still runs, and the failure is now written to ~/.amc/trampoline-uncontained.jsonl (capped, so it cannot grow without limit) and reported here.

Without that section the two states are indistinguishable — a shell with no job looks exactly like one with a job — so the only way to learn that containment had stopped working was to notice an orphan later. The reason is named on every row:

Reason What it means
job-create-failed Windows refused to create the job object.
job-assign-failed The shell could not be placed in the job.
forced-by-env Test seam only. Set by AMC_TRAMPOLINE_FORCE_UNCONTAINED, which nothing in production ever sets; it exists so the recording path itself can be proved against the real binary.

A non-empty list here does not mean an orphan exists — it means the net had a hole for that one command, and it is worth knowing which commands hit it before the next one escapes.

Turning enforcement on

Watch the shadow census for a full day. If every "would-reap" row is a tree you would have ended by hand, flip the setting orphanToolTreeReaperEnforce to true (a settings change, approval-gated like any other — PATCH /settings/orphanToolTreeReaperEnforce with an approval note over the CLI server). Flip it back the same way at any time. To stop the whole pass, set AMC_DISABLE_ORPHAN_TOOL_TREE_REAP=1.

With enforcement on, each tree is re-checked against a fresh process census immediately before it is ended (same process id, same start time; the command line is consulted only when a start time is unknown), at most ten trees per sweep, and a tree whose kill fails three times is set aside rather than retried forever. A sweep that ends ten or more trees at once raises one informational inbox card, because a recurring storm means something upstream is still stranding them.

The one-off command

The same classifier is available by hand:

npm run orphans:reap                 # dry run: every candidate with its verdict and the reason
npm run orphans:reap -- --enforce    # end the trees that pass, after re-checking each one

Outside the running app the session Job cannot be seen, so the hand-run prints that condition as n/a and relies on the helper shape instead — read the dry run in full before enforcing.

What is never touched

Anything whose launcher is still alive; any process that is not one of the four helper shapes; anything younger than 15 minutes; dev servers, watchers, monitors and unknown script names; anything a gate or gate watch owns; any tree with git write work or a half-finished git operation; and, under enforcement, anything outside the session Job.

Related: Job Object orphan-kill (Windows) — why these trees survive until the app exits in the first place.

Related

Last verified 2026-10-06