Agent-Broom Standalone CLI
Agent-Broom v1 is the buildable spec that turns Kevin's cleanup stack into a single small, zero-AI, dependency-light CLI — in the exact shape of port-whisperer — that runs fully on its own, is callable by an agent through a stable JSON contract, ships one thin skill wrapper, and gives Local Search CLI a cleanup path to depend on.
This page is the build program. It is not the current-state import page — that is the Agent Broom tool page, which documents the vendored repo at commit 1bab484c38a3061826cbb93cec591c5d786a48db. This spec describes the next version: Kevin-Liu-01/Agent-Broom promoted from "a skill that reminds an agent to run a script" into a standalone tool that stands on its own like port-whisperer does, with the agent hook layered on top rather than baked in.
The originating instruction: "make sure local search cleans up after itself and instances ... use and examine the open source github repo port-whisperer ... and then my custom tool: Agent-Broom. be sure that agent broom works fully fine on its own, works like port whisperer first in that its a cli that then can be called by an agent, update the skills to work better, and then update local search with the cleanup scripts and skills for agents." Source: Discord "Straight Fats", 2026-07-20 19:44
Ownership Decision: Extend devclean, Supersede The Loose Split
The cleanup domain currently has four surfaces with overlapping identity: the DevClean reference tool (external ImL1s/devclean), the Agent Operations Skills skill (the wiki's MECE process-hygiene owner), the Agent Broom tool page (the vendored source import), and the Agent Process Tracking, Audit, And Cleanup concept (the rationale). The build introduces one more thing they can all point at: a real published binary.
The decision, stated MECE so nothing forks:
| Surface | Role after v1 | History |
|---|---|---|
| Agent-Broom CLI (this page) | Canonical implementation owner of agent cleanup: the standalone binary, its command surface, its agent-callable contract, and its agent-broom.json capability manifest. |
New forward-looking owner. |
| DevClean | Design ancestor, preserved. Agent-Broom extends devclean's four-mode shape (safe orphans / --deep / --optimize / --disk). We do not re-import devclean; we credit it. |
Unchanged; keep the citation. |
| Agent Broom tool page | Source-import receipt, preserved. Records what the repo contained at import. This project page supersedes it as the description of where the repo is going, not as evidence of where it was. | Kept append-only. Add a timeline entry pointing here; do not rewrite its body. |
| Agent Operations Skills | Skill router / memory hook, preserved as the wiki MECE owner. After v1 it delegates to the installed agent-broom binary instead of carrying its own script copies; the vendored references/agent-broom/ stays for cross-harness bootstrap. |
Kept; delegation is a later, separate edit. |
| Agent Process Tracking, Audit, And Cleanup | Rationale concept, preserved. The "you started it, you stop it" ownership rule and the ariadne CPU incident stay the durable why. | Unchanged. |
Justification. devclean is an external tool with a shape worth copying, not a thing Kevin controls — so extend (borrow the mode split, keep the credit) is correct, and supersede would be wrong because we cannot own someone else's repo. The agent-broom tool page describes an earlier repo state; the instruction explicitly asks to change that state ("work fully fine on its own ... works like port whisperer"), so this project page supersedes it as the authority on direction while its timeline is preserved as evidence. Collapsing the four surfaces into one page would destroy provenance; keeping them with one clear implementation owner keeps the graph MECE.
Graph note for the indexer. This file's slug is
projects/agent-broom; the tool page istools/agent-broom. Both share the leafagent-broom, so a bare[[agent-broom]]now resolves to two leaves and will render ambiguous until a redirect or rename is added. Recommended follow-up (out of scope for this write, which creates only this file): addagent-broom -> tools/agent-broomtowiki/meta/wiki-redirects.json, or retitle this page's canonical link target, before the nextbuild-indexrun.
port-whisperer As The Design Reference
port-whisperer is the north star for shape, not features: 2,467 lines of JavaScript, 3 dependencies, zero AI, 864 GitHub stars. The lesson Kevin drew from it — "I build agent infrastructure for a living, but the thing people actually use is a ports checker" — is that a small deterministic CLI that does one boring job well beats a clever agent-shaped tool. Agent-Broom v1 adopts port-whisperer's constraints as hard design rules:
- Standalone first. It must run and be useful with no agent, no LLM, no API key, and no network. An agent calling it is a second-class consumer of the same binary a human runs by hand.
- Zero AI in the tool. No model calls in any code path. All intelligence is deterministic classification (process kind, ownership, regenerability). The skill may be read by an agent; the binary never reasons.
- Dependency-light. Target ≤ 3 runtime dependencies, mirroring port-whisperer. Prefer the platform (
ps,lsof,kill,du,/proc) over libraries. Ship as a single distributable. - One obvious verb per job.
list,audit,ports,stop,artifacts,devclean,doctor— a reader should predict what each does from its name. - Boring output. Human-readable tables by default; a machine contract behind
--json. No spinners, no color-dependence, no interactivity required for the core path.
Where Agent-Broom deliberately goes beyond port-whisperer: a process ledger (ownership accounting, not just a live port scan), the four-mode devclean machine cleanup borrowed from DevClean, build/cache artifact reclamation, and the agent-callable contract + skill. port-whisperer answers "what is on my ports"; Agent-Broom answers "what did agents leave running, and can I safely sweep it."
Command Surface
Single binary agent-broom (installable to PATH; also runnable as bin/agent-broom from a clone, exactly like today). Every command works standalone.
# inventory & audit (read-only, always safe)
agent-broom list # recorded agent-owned processes from the ledger
agent-broom audit # ledger + live localhost listeners + test/dev/browser classification
agent-broom ports # port-whisperer-style: what is listening, on which port, owned by what
agent-broom ports --port 3000 # who holds a specific port
# ownership accounting
agent-broom add --pid <PID> --kind dev --port <PORT> --purpose "<why>" -- <command>
agent-broom prune # drop dead entries from the ledger (no process signals)
# process cleanup (dry-run first; mutation gated)
agent-broom stop # report the process groups it WOULD stop
agent-broom stop --kill # actually SIGTERM (then SIGKILL stragglers) by process group
agent-broom stop --port 3000 --kill
# disk / artifact cleanup (dry-run first; mutation gated)
agent-broom artifacts # report reclaimable regenerable build/cache output + sizes
agent-broom artifacts --clean
# machine-wide dev cleanup (devclean shape; dry-run first)
agent-broom devclean # safe orphaned dev/MCP/frontend/mobile processes only
agent-broom devclean --deep # heavy daemons: Gradle, Kotlin LSP, Flutter, FVM, simulators
agent-broom devclean --optimize # crash-reporter settings, Crashpad dumps, known bg agents
agent-broom devclean --disk # global dev caches + project build artifacts
agent-broom devclean --apply # execute the reviewed targets
# proof
agent-broom doctor # self-check: deps present, ledger writable, protect-list intact
agent-broom --version
Global flags (the agent contract lives here)
| Flag | Meaning |
|---|---|
--json |
Emit the machine contract (see below) instead of tables. Valid on every command. |
--yes / -y |
Non-interactive confirm for a destructive run; equivalent to answering the confirm prompt "yes". Required for automation. |
--dry-run |
Force report-only even on a mutation verb. Default for stop/artifacts/devclean when no apply flag is given. |
--quiet |
Suppress human decoration; combine with --json for clean piping. |
--scope <path> |
Restrict process/artifact matching to a repo root, so a run cannot reach outside the intended tree. |
Cleanup Targets And Safety Model
Targets are grouped so each has an explicit, reviewable classification. Nothing is inferred from a name alone at the moment of killing — the ledger and the protect-list arbitrate.
| Class | Examples | Default action |
|---|---|---|
| Recorded agent processes | Anything agent-broom add tracked (PID, PGID, port, purpose, cwd, repo root) |
Reported; stopped by process group only when clearly stale and owned. |
| Stray dev servers | Next, Vite, Turbo, Bun, Uvicorn, Rails, pnpm/npm/yarn dev on localhost |
Reported by audit/ports; keep the one the user is actively using. |
| Hung test/watch runners | Vitest, Jest fork workers pinned near 100% CPU | Reported; the highest-value kill target (the ariadne incident). |
| Orphaned MCP / helpers | dead-parent MCP processes, orphaned automation Chrome under ms-playwright/mcp-chrome |
Reported; automation browsers you spawned are yours to close. |
| Regenerable artifacts | .turbo, .next, .vite, dist, build, out, .output, *.tsbuildinfo, .eslintcache, coverage, test-results, playwright-report, node_modules/.cache |
Sized and reported; deleted only with artifacts --clean, never over git-tracked paths. |
| Machine daemons/caches | Gradle/Kotlin daemons, Flutter/FVM, simulators, global dev caches | Behind devclean --deep/--disk, dry-run until --apply. |
Protect-list (never touched without explicit proof of safe-orphan): the editor/IDE (Cursor, VS Code), the agent runtime (Codex, Claude Code), the user's interactive shell, and shared MCP servers (playwright-mcp, chrome-devtools-mcp). Generic crashpad_handler with PPID=1 is not a safe-orphan target — on macOS those are normal Codex/Cursor/Chrome/Slack/Discord helpers — so Crashpad cleanup stays behind --optimize for review.
Safety invariants (identical for human and agent callers):
- Dry-run is the default for every mutating verb. A destructive action requires either an interactive "yes" or
--yes. - Kill by process group (
kill -TERM -<PGID>), SIGTERM before SIGKILL, so a test tree dies at the leaf worker that holds the CPU, not just the parent. - Delete only regenerable artifacts, and never a path that still contains git-tracked files — cleanup can never destroy source.
--scopebounds the blast radius to a repo root when set.- The protect-list is hard-coded, not configurable away by a flag.
Agent-Callable Contract
The binary is the interface; the agent is just another caller. The contract is designed so an agent (or Local Search CLI, or a CI step) can drive cleanup without screen-scraping tables — mirroring how Agent-Ping is a one-file CLI usable from any shell.
- Invocation: any command plus
--json. Destructive runs additionally require--yes(no TTY prompt is available to an agent). - stdout: a single JSON object. stderr: human logs only. This split lets an agent parse stdout blind.
- Exit codes:
0success / nothing to do;10targets found in a dry-run (actionable, not an error);20partial (some targets acted on, some skipped/protected);1usage error;2environment error (missinglsof/ps, unwritable ledger — whatdoctordiagnoses). Distinct codes let an agent branch without parsing. - Idempotent + re-entrant: two agents running
auditconcurrently must not corrupt the ledger (advisory lock onledger.tsv). - No prompts, no network, no AI on the agent path.
Response envelope (stable keys; version it):
{
"tool": "agent-broom",
"version": "1.0.0",
"command": "audit",
"dryRun": true,
"scope": "/Users/kevinliu/repos/example",
"findings": [
{
"id": "pgid:48213",
"class": "test-runner",
"pid": 48213, "pgid": 48213, "port": null,
"cpu": 98.4, "etime": "10:52:11",
"owner": "agent", "protected": false,
"command": "vitest run --watch",
"recommendation": "stop",
"reason": "hung fork worker, no output consumer"
}
],
"protected": [{ "class": "mcp", "command": "playwright-mcp", "reason": "shared IDE server" }],
"reclaimableBytes": 38654705664,
"actions": { "available": ["stop --kill"], "applied": [] }
}
The recommendation field is deterministic classification, not a model opinion. An agent reads findings[].recommendation, decides policy, then re-invokes with --yes to act.
Skill Wrapper
The skill stays a thin memory hook, per the existing design rule — do not move deterministic logic into prompt text. v1 changes only the entrypoint and the "when": it points at the installed binary and teaches the JSON path.
- Ships at
skill/SKILL.mdin the repo (for other harnesses) and is vendored into Agent Operations Skills'sreferences/agent-broom/. - Triggers (unchanged intent): before starting a localhost/dev server, before ending a turn that spawned long-runners, high CPU/memory, low disk, or when the user says "what is running", "devclean", "clean up terminals", "too many localhosts", "free disk space". This aligns with End Of Turn Hygiene.
- Loop it teaches:
agent-broom audit --json-> read findings ->agent-broom addfor anything you start -> before turn endaudit --jsonagain -> act only with--yeson reviewed targets -> never touch the protect-list. - The in-wiki MECE owner remains Agent Operations Skills; after v1 its
agent-hygiene.shbecomes a shim that execs theagent-broombinary when present and falls back to the vendored scripts otherwise. That delegation is a separate follow-up edit, not part of creating this spec.
Integration With local-search-cli
Local Search CLI (the proposed cargo-published local browser-search crate) must "clean up after itself and instances." Agent-Broom is its cleanup dependency rather than local-search reimplementing process teardown.
- Registration: when local-search spawns a browser instance or a local index server, it calls
agent-broom add --kind search --port <PORT> --purpose "local-search index" -- <command>so the instance is owned in the ledger the moment it exists. - Self-clean on exit: local-search's own shutdown calls
agent-broom stop --scope <its-root> --kill --yesto guarantee no orphaned browser/index process survives a crashed or cancelled query. - Sweep command: local-search ships a
search cleansubcommand that is a thin call toagent-broom audit --jsonfiltered toclass == "search", thenstop --yes— so the two tools share one cleanup implementation. - Skill handoff: the local-search skill references the Agent-Broom skill for the cleanup loop instead of duplicating it, keeping the process-hygiene rule in one place.
This is the concrete meaning of the instruction's last clause — "update local search with the cleanup scripts and skills for agents" — realized as a dependency edge, not copied code.
Proof, Doctor, And Test Fixtures
Per the Doctor Pattern, the tool proves itself before it is trusted.
agent-broom doctorchecks: required binaries present (ps,lsof/ss,kill,du), ledger path writable, protect-list loaded and non-empty, advisory lock works, and--jsonschema validates. Exit2on any failure. This is what a self-heal loop (Agent Capability Registry health) polls.- Fixtures (deterministic, no real killing): a fixture harness spawns disposable sentinel processes (
sleep-based stand-ins for a dev server, a hung test worker, an orphaned browser) into a sandbox process group, plus a temp repo tree seeded with fake.next/.turbo/git-tracked files. Tests assert: (a)audit --jsonclassifies each sentinel correctly; (b) a protected-name sentinel is never inrecommendation: stop; (c)stop --killon the sandbox group terminates only sentinels; (d)artifacts --cleandeletes the regenerable dirs and refuses the git-tracked path; (e)--scopeexcludes an out-of-tree sentinel; (f) exit codes match the table. - Golden JSON: snapshot the
--jsonenvelope shape so the agent contract cannot silently drift; a schema change must bumpversion. - Cross-platform: matrix macOS + Linux, since process/port introspection differs (
lsofvsss,psflags,/proc).
Capability-State Fields
For Agent Capability Registry / Full Corpus Workflow and Capability Program lifecycle tracking (captured -> reviewed -> workflow-bound -> installed -> configured -> healthy -> adopted). The port-whisperer facts are the review evidence; Agent-Broom is Kevin's own repo mid-build.
capability: agent-broom-cli
owner_repo: Kevin-Liu-01/Agent-Broom
kind: cli + skill
ai: none # hard requirement, mirrors port-whisperer
dependencies: "<=3 runtime" # design target
reference_tool: port-whisperer # 2467 LOC / 3 deps / 0 AI / 864 stars, no wiki owner
design_ancestor: devclean # mode shape (safe/deep/optimize/disk)
agent_callable: true # --json contract + deterministic exit codes
skill: skill/SKILL.md # thin memory hook
consumers: [local-search-cli, cleanup-terminals-browsers]
state: reviewed # spec written; not yet built to v1
install_state: source-vendored # references/agent-broom/ @ 1bab484...
healthy: pending # gated on `agent-broom doctor` green in CI
adopted: pending # gated on cleanup-terminals-browsers delegating to the binary
Phased Build Order
- Phase 0 — Baseline the reference. Read port-whisperer end to end (2,467 LOC, 3 deps). Extract its argv parsing, port-introspection, and output patterns; confirm the zero-AI / dependency-light budget is realistic on top of the existing shell logic. Deliverable: a short shape note in the repo.
- Phase 1 — Standalone core. Ship
list,audit,ports,add,pruneas a single binary that runs with no agent and no network. Ledger read/write with advisory lock. Human tables only. This alone must be "fully fine on its own." - Phase 2 — Gated mutation. Add
stop,artifacts, anddevclean(four modes) with dry-run default,--apply/--kill/--cleangates, process-group kill, git-tracked guard,--scope. Port the protect-list. - Phase 3 — Agent contract. Add
--jsonto every command, deterministic exit codes,--yesnon-interactive confirm, stdout/stderr split, golden-JSON snapshot. Now agent-callable. - Phase 4 — Doctor + fixtures.
agent-broom doctor, the sentinel-process fixture harness, and the macOS/Linux CI matrix. Nothing is "adopted" until doctor is green. - Phase 5 — Skill + registry. Rewrite
skill/SKILL.mdto point at the binary and teach the JSON loop; update the vendored copy under Agent Operations Skills and regenerate the skill registry per Generated Surface Contract. - Phase 6 — local-search wiring. Land the
add-on-spawn,stop-on-exit, andsearch cleanedges in Local Search CLI; confirm no orphaned instances survive a cancelled query. - Phase 7 — Delegation + supersede. Point
cleanup-terminals-browsers'sagent-hygiene.shat the installed binary (fallback to vendored scripts), add the redirect/rename that de-ambiguates[[agent-broom]], and append supersede notes to the tool page timeline. Flipstate: adopted.
Each phase is independently shippable and leaves the tool usable; that ordering is itself the port-whisperer discipline — a working small thing at every step.
Timeline
- 2026-07-21 | Spec created. Decided Agent-Broom v1 extends DevClean (mode shape, credited) and supersedes the Agent Broom tool page as the direction authority while preserving its import history; port-whisperer (2,467 LOC, 3 deps, zero AI, 864 stars) is the standalone-CLI design reference; defined the command surface, safety invariants,
--jsonagent contract, thin skill wrapper, Local Search CLI cleanup integration, doctor + fixtures, capability-state fields, and a seven-phase build order. Flagged theagent-broomleaf-slug ambiguity for a follow-up redirect/rename. Source: Discord "Straight Fats", 2026-07-20 19:44; https://github.com/Kevin-Liu-01/Agent-Broom; port-whisperer GitHub