agentwatchdog

Record of observation

Nothing on this host gets to decide whether it’s audited.

agentwatchdog watches AI coding agents from outside the agent — from /proc, where cooperation isn’t a variable. It never reads your prompts, and there is a test that fails if it ever does.

Scan · 4 processes
/proc/2759430/cmdline claude -p "rotate the staging database credentials before Friday" --model opus secret_flags-p takes a prompt
/proc/821321/cmdline codex exec "summarise the incident timeline for the postmortem" --sandbox read-only positional · default-denycodex carries prompts as bare arguments
/proc/3104882/cmdline aider -m "patch the auth bug" --api-key sk-EXAMPLE-NOT-A-REAL-KEY-000 secret_flags · credential shapemasked twice over
/proc/3104960/cmdline spindle chat "draft the migration plan" --task "internal" no fingerprintan agent we have never seen — every positional denied anyway

Synthetic command lines, real rules. In the tool itself the raw string is never written at all — redaction happens before anything reaches disk, so there is no “before” on your host to reconstruct.

Writes nothing. Sends nothing. Safe on the host you’re suspicious about.

The gap

The tooling you already have needs the agent’s cooperation.

In-agent observability — OTel exporters, hooks, wrapper commands, proxies — works only while the agent plays along. Skip the environment variable, don’t install the hook, call the binary directly, and it goes blind. The runaway cron job, the misconfigured unit and the account that shouldn’t be here are precisely the cases that never play along.

Vantage point
Inside the agent process
The host’s /proc
Can be bypassed
Yes — by not cooperating
No. A process that exists is seen
Dependencies
A collector, Docker, Node packages
None. Python 3 standard library and systemd
Prompt content
Some read session transcripts verbatim
Never read; redacted before anything is written
Answers
Tokens, cost, session detail
Who ran what, spawned by whom, behaving how
Built for
The developer at the keyboard
The operator of the host

Both are worth having. If you want per-token cost dashboards, use an OTel-based tool — this is not that. This is the audit trail for the machine.

Detectors

Six things worth waking up for.

Every alert carries the command to run next. Repeats are suppressed per situation rather than per scan — one account running fifty agents is one finding, because a monitor that fires every sixty seconds is a monitor somebody turns off.

unexpected_user

Critical

An account outside ALLOWED_USERS ran an agent. The alert carries loginuid, so “alice ran an agent as root via sudo” arrives as a fact instead of a mystery.

parent_spawn_storm

Critical

One parent process keeps spawning agents. No human does this — it is a restart loop, and it bills you for every attempt. The alert carries the ancestry, because the agent is the symptom and the parent is the bug.

user_high_frequency

Warning

One account is starting agents faster than a person types.

long_running_process

Warning

A non-interactive agent outlived its limit. Interactive and SDK sessions are exempt: a session someone is sitting in front of is not a hung process, and treating it as one makes this useless on exactly the hosts it is for.

high_cpu · high_mem

Warning

Sustained abnormal resource use. Measured as a lifetime average with a minimum sample age, so the spike every agent produces while starting up doesn’t become an alert every agent produces.

agents_during_high_load

Warning

Several agents landing on a host that is already struggling. No single process is at fault, which is exactly why nothing else reports it.

The privacy contract

Five promises, each with a test that fails if it breaks.

This thing reads command lines for a living. That is only acceptable if the limits are enforced rather than described — so every one below is wired to a test, and CI runs them as their own job, where a failure is impossible to miss.

test_environ_is_never_opened

Environment variables are never read.

/proc/PID/environ is not opened on any code path. The test records every open() during a scan and fails if that file appears. API keys living in the environment cannot pass through this tool.

test_prompt_never_survives_redaction

Prompts never reach disk.

Command lines are redacted before they are written, using per-agent rules — because every CLI keeps its prompt somewhere different.

test_unknown_flag_is_assumed_boolean

Positional arguments are denied by default.

An argument survives only if a fingerprint vouches for it as a known subcommand. An unrecognised flag is treated as boolean, so the token after it is covered too. An agent released after this version leaks nothing; it only shows up with less detail.

test_credentials_are_redacted_in_any_position

Credential shapes are masked wherever they appear.

Provider key prefixes, JWTs and long opaque tokens are masked even in positions no rule anticipated — which is where a credential ends up when somebody pastes a command wrong.

test_export_reports_only_permitted_keys

What may leave the host is anonymous by construction.

The summary is assembled from scratch into a fixed shape rather than filtered out of an event, then checked against a key allowlist at runtime. An export that cannot be proven anonymous is refused, not published.

Run agentwatchdog selftest to watch these hold against the agents actually running on your machine, not against ours.

agents.d

Detection is data, not code.

Each agent is a JSON fingerprint describing how to recognise it and where it carries its prompt. Operators can add or correct one in /etc/agentwatchdog/agents.d without waiting for a release, and a fingerprint plus one redaction test is the easiest useful pull request this project takes.

AgentFlag tableWhere the prompt lives
Claude CodeVerified against the binaryBare positional, and -p
OpenAI Codex CLIVerified against the binaryPositional, at top level and after exec
aiderVerified against 0.86.2-m, --message, --msg
Gemini CLIFrom documentation-p, --prompt
OpenCodeFrom documentationPositional after run

Two traps the verified tables caught, as a caution against writing these from memory. Codex takes a prompt as a positional at the top level, not only after exec. And Codex’s -p is --profile, while Claude Code’s -p is the prompt — port one agent’s rules to the other and the tool dutifully masks a profile name while writing the prompt to disk. Both are now regression tests.

Install

Look first. Install second.

One file, nothing to build, no dependency beyond python3. Linux only — the design is /proc.

1 · Look

$ curl -fsSLO https://github.com/Ymakercc/agentwatchdog/releases/latest/download/agentwatchdog.pyz
$ chmod +x agentwatchdog.pyz
$ ./agentwatchdog.pyz dry-run
# writes nothing, sends nothing, updates no state

The complete output of a scan, on your host, before the tool has done anything at all.

2 · Check

$ ./agentwatchdog.pyz selftest

Proves the redaction rules against every built-in fingerprint and against the command lines actually running on the machine you are standing on.

3 · Install

$ sudo mv agentwatchdog.pyz /usr/local/bin/agentwatchdog
$ sudo agentwatchdog install
# systemd timer, config, log rotation. Alerts stay local
# until NOTIFY says otherwise.

Point it at the host you’re least sure about.