---
title: Runaway agent commands (the "has run N minutes" card)
---

# Runaway agent commands (the "has run N minutes" card)

## What it is

Agents run shell commands all the time. Most finish in seconds. Occasionally one runs away — a
search through a project's whole history, or a listing of a folder with a million files — and keeps
running for half an hour. While it runs it can slow **every** agent on the machine, and nothing about
its own session looks wrong.

Omniscio watches for that. About every two minutes it looks at every command your agents are running
right now. When one has run **ten minutes or more** and either

- it is a search or listing (such as `grep`, `rg`, `find`, `ls` or a git history read) that is still
  busy while the other agents are measurably slowing down — an honest search finishes in seconds, or
- it has the shape of a search known to run away (for example a history search with no file named,
  or a recursive listing with no depth limit),

you get **one** inbox card: *"An agent command has run 23 minutes and is still busy while the other
agents are slow"*, naming the session and showing the command. The card goes away by itself when the
command finishes.

The card says only what Omniscio measured: how busy the command was over the last two minutes (a
share of one processor core, and file operations a second) and that the other agents are slow right
now. It never claims this command is the one slowing them — nothing measures that, so the card does
not say it.

A build, a test run, an install, a merge gate or a script never gets this card just for being busy.
That work is expected to run long and hard — measured on a busy machine it is often busier than a
real runaway listing — so being busy says nothing about it. It still gets the card if its command
contains a search with a known runaway shape.

## Commands left running after their tool call ended

When an agent's command takes too long, its tool call gives up and its shell ends — but the program
the shell started can keep running with nobody waiting for it. A recursive search left this way once
kept a processor busy for almost two hours.

Omniscio watches those too, judged by exactly the same rules as a running command. The card reads
*"A command left running after its tool call ended has run 14 minutes and is still busy while the
other agents are slow"*. Stop ends that leftover program and everything it started; the agent's
session keeps running. When Omniscio saw the original command, it judges the leftover on what the
agent actually typed. When it did not, the leftover is never stopped automatically, because it cannot
tell whether the program was writing its output to a file.

## When an agent starts a second copy

An agent that puts a long command in the background sometimes loses track of it. Git Bash's `ps`
shows no program arguments, so a check like `ps | grep probe.mjs` finds nothing while the command is
still running, and the agent starts it again — one agent ran three copies of an hours-long check this
way.

So when an agent's command starts a program that is byte-for-byte the same as one the same session
has already been running for ten minutes or more — still under its tool call or left running after
it — Omniscio tells **that agent** once. The message names the program, when each copy started and
its process number, says the first copy had not died, and says how to stop the extra copy safely. It
never shows the command itself, because a command can carry a password the agent was never meant to
see. It comes after two checks in a row see both copies, and reaches a busy agent when its current
turn ends. No card is raised for you; nothing is stopped.

Only the program a command started counts — never the small helpers every command shares (a console
window host, `tail`, `grep`, `sleep`) — and the same command in another session, or two programs one
command deliberately started together, never count.

## What Stop does

- It ends **only that command** — including every program the command started (a pipeline such as
  `git log … | grep …` is treated as one command).
- It **never** ends the agent's session, its shell, or its tool servers. The agent sees its command
  fail, not succeed, and it receives a short message explaining what was stopped (named by when it
  started — never by the command itself), after how long, why, and how to run it again with limits.
- It re-checks the command at the moment you press it. If the command already finished, or something
  else is now running in its place, nothing is stopped and the card is cleared.
- It never closes an app you are using. If a command started one, that part is left alone and the
  card stays so you can see it did not fully stop.

Stop works from your paired phone too, rate-limited the same way as interrupting a session.

The command on the card is exactly what the agent typed, up to 600 characters. A longer one is cut,
and the cut always ends with `…`, so what you see never passes for the whole command.

## What Omniscio stops on its own

Only **read-only searches and listings** (such as `git log`, `grep`, `rg`, `find`, `ls`, `du`),
only after **twenty minutes**, only while they are busy **and** the other agents are slowing, and at
most two per check. It looks at the whole command the agent typed, so a search whose output is
written to a file is not read-only and is never stopped automatically. If an automatic stop cannot
finish, the command keeps running and you get its card instead, so you can decide.

Anything that writes, installs, builds or tests — a commit, a rebase, an install, a test run — is
**never** stopped without you pressing Stop.

## Turning it off

It is on by default, and two settings control it:

- `runawayCommandWatchEnabled` turns the whole watch off — no cards and no stops.
- `runawayCommandAutoStopEnabled` keeps the cards and the Stop button but turns off only the
  automatic stops.

Neither has a switch on a Settings screen; ask an agent to change one for you. Because the watch
polices agents' own commands, an agent's request to change either one reaches you as a card to
approve rather than taking effect on its own. For a developer, the environment variables
`AMC_DISABLE_RUNAWAY_COMMAND_WATCH=1` and `AMC_DISABLE_RUNAWAY_COMMAND_AUTOSTOP=1` do the same.

## Where the record is

Every long-running command the watch judged — and every stop — is recorded once per verdict in
`~/.amc/orphan-tool-tree-reaper.jsonl` as a `"kind":"long-runner"` row, with the session, how long
it had run, how much processor time it used, and the command. A command left running after its tool
call ended carries `"orphaned": true` and the process it hangs from as `anchorPid`. Each time an agent
is told about a second copy, the first copy gets a `"verdict":"told-duplicate"` row naming the copy's
process.

Every row also carries the most memory the command used (`peakMemMb`, counted from the first time
the watch saw it, or `null` when no memory reading was available), whether it ran the whole check
suite (`fullSuite`), and whether it did heavy work on this PC — 4 GB or more (`heavyLocal`). The
newest finished row that is both is what the "run my checks on this PC" approval card shows as the
cost of a full check run here ([cloud-enforce-window.md](cloud-enforce-window.md)).
