ranwhat watch

See the risky commands Claude Code already ran.

ranwhat watch reads what Claude Code and twenty-nine other coding agents have already written to disk, the audit trail they keep anyway, and reports the sixteen kinds of action worth a second look. It changes nothing.

$ ranwhat watch --days 30
Install
01 / Detection

Sixteen things worth interrupting you for.

This isn't antivirus. There's no adversary and no signature, because you asked the agent to do things. So it doesn't guess whether an action was allowed. It raises the ones you'd want to know about either way.

RuleSeverityWhy it's on the list
Credential access
.env · ~/.aws/credentials · id_rsa
Critical Read a file whose only purpose is holding secrets. The contents are now in a context you don't control, and in the transcript too: find and mask them with ranwhat clean. Then block the next read.
Secret-shaped string in a tool call
sk_live_… · ghp_… · AKIA…
Critical A credential-shaped value appeared verbatim in a tool call. Even if the call was benign, the value is now in the transcript.
Package or release published
npm publish · twine upload · docker push
Critical Something reached a registry other people install from. Supply-chain reach, usually irreversible.
Cloud resource destroyed or modified
terraform destroy · kubectl delete · aws iam attach-…
Critical A write or delete against live infrastructure, including IAM changes, terraform apply -auto-approve and DROP TABLE.
Financial API called
stripe charges · refunds
Critical With a live key, each of these moves real money.
Log or history tampering
history -c · cloudtrail stop
Critical An action whose effect is removing the record of other actions.
Cloud instance credentials requested
169.254.169.254/…/security-credentials · …/service-accounts/default/token
Critical A request to a cloud metadata service for the role the machine runs as, on AWS, GCP, Azure, Alibaba or Oracle. The short-lived token that comes back is in the transcript, ready to use, and grants whatever the role can. A plain metadata read, an instance id or a region, is not reported.
Destructive git
push --force · reset --hard
High History rewriting. The class of action that destroys the record of what else happened.
Recursive deletion
rm -rf · find -delete
High Recoverable only if something else was backing it up. Severity follows the target: rm -rf build is not reported, rm -rf ~/Documents is high, rm -rf "$HOME" is critical.
Local file sent to the network
curl -d @file · curl -F file=@…
High File contents sent outbound in one command. That shape, whatever the intent.
Downloaded script run unread
curl … | sh · bash <(curl …)
High A script fetched from the network and handed straight to a shell or interpreter. Whatever the server sent at that moment ran with your permissions, and nothing on disk shows what it was. Saving it to a file and running it in a later call is two calls, and is not reported.
Files made writable by every user
chmod -R 777 · chmod o+w
High Severity follows the reach: chmod -R 777 / or ~ is critical, a recursive change is high, one file or directory is medium, and a scratch path under /tmp is not reported. chmod 755 and +x never are.
Container data wiped
docker system prune -a · docker volume rm
High Volumes, or every container, removed: docker system prune --all or --volumes, volume rm or prune, compose down -v. A plain prune, or one named container, is not reported.
Decoded command run
base64 -d | sh · eval "$(… | base64 -d)"
High A command hidden in base64, hex or printf escapes and handed straight to a shell, eval or an interpreter, so the agent's own text shows only the encoding. watch decodes what it can without running it and judges the result by the other rules: an encoded rm -rf ~ is reported as that deletion too. Decoding to a file or to read it (base64 -d > key.pem, | jq) is not reported.
Startup or scheduled job installed
crontab - · launchctl load · schtasks /create
High Something set to run again on its own, at login, at boot or on a schedule, with your permissions, after the session has ended: a crontab, a launch agent, a systemd unit, a Windows service, a Run key. A change to a shell startup file is medium: an export PATH line appended to ~/.zshrc is medium, one that runs curl … | sh in every new shell is high. A packaged service enabled by name (systemctl enable docker) is medium.
Agent guardrails loosened
--dangerously-skip-permissions · bypassPermissions · ranwhat hook uninstall
High An agent changed what it, or another agent, may do without asking you: one launched with its approvals off, a broad allow rule added, a deny rule taken out. Critical when it switches off the hook itself, every hook, or every prompt in your user settings, so the hook asks before a call that shows its own removal. A settings file rewritten whole with other settings, by a call that does not show what it replaced, is medium. So is an MCP server or a hook added.

watch looks back over history after the fact, so it is not live monitoring of Claude Code or any other agent, and it blocks nothing. To have a call these rules rate high or critical wait for your yes before Claude Code runs it, install the opt-in hook. For a record kept while the agent works, add a hook or OpenTelemetry, as the Claude Code audit log guide shows.

02 / Precision

A watcher that cries wolf gets muted in a day.

So three things that look dangerous are not treated as actions. The first watch build, run on a real machine's history, flagged 6 findings, and these were the 3 false positives among them.

grep "rm -rf" src/

Searching for a string isn't running it. Search tools without an action flag are suppressed.

python3 -c "…rm -rf…"

The payload is Python source. bash -c is the exception: that really is shell, so it recurses in.

cat > f.sh <<'EOF'

A heredoc body is data being written. Writing a script that contains a command isn't running it.

On real history A later release reported 15 findings on one machine's 90-day history. Eleven were true deletions of build and temp directories that nobody would want to read, so deletions are now ranked by target. After that change the same history gave 4, and all four were real.
Evidence Every finding carries surrounding context. rm -rf on its own tells you nothing. The target is the point. A secret in it is masked: every value clean finds anywhere in your history, known by an index of salted fingerprints in ~/.ranwhat/known.
Test suite Written as invariants rather than expected output.
03 / Sources

Reads the agents already on your machine.

No wrapper, no proxy, nothing in your critical path unless you install the hook. It reads what each agent already wrote to disk, all of them by default.

AgentLocationFormatStatus
Claude Code ~/.claude/projects/*/*.jsonl, and each session's subagents/ ($CLAUDE_CONFIG_DIR) JSONL Shipped
Codex ~/.codex/sessions/ and archived_sessions/ ($CODEX_HOME); its prompt history, shell snapshots and thread index searched for secrets JSONL; SQLite read only; .jsonl.zst read only, on Python 3.14 or with the zstd command Shipped
Gemini CLI ~/.gemini/tmp/<project>/chats/ ($GEMINI_CLI_HOME) JSONL, JSON Shipped
Antigravity ~/.gemini/antigravity-cli/brain/, and the same under antigravity and antigravity-ide JSONL Shipped
GitHub Copilot CLI ~/.copilot/session-state/<session>/events.jsonl ($COPILOT_HOME) JSONL Shipped
GitHub Copilot in VS Code <editor>/User/workspaceStorage/<workspace>/chatSessions/ and globalStorage/emptyWindowChatSessions/ ($VSCODE_PORTABLE, $VSCODE_APPDATA) JSONL, JSON Shipped
Cursor The editor's Cursor/User/globalStorage/state.vscdb, and ~/.cursor/chats/ for cursor-agent SQLite Shipped, secrets read-only
Windsurf ~/.windsurf/transcripts/, written when Windsurf's post_cascade_response_with_transcript hook is on JSONL; Cascade's own history is encrypted and not read Shipped
Cline The editor's globalStorage/saoudrizwan.claude-dev/tasks/, and ~/.cline/data ($CLINE_DATA_DIR) JSON Shipped
Roo Code The editor's globalStorage/rooveterinaryinc.roo-cline/tasks/ JSON, text Shipped
Kilo Code ~/.local/share/kilo/kilo.db and the older storage/ JSON files ($XDG_DATA_HOME/kilo, $KILO_DB) SQLite, read only; JSON Shipped
OpenCode ~/.local/share/opencode/ ($XDG_DATA_HOME/opencode, $OPENCODE_DB) SQLite, read only; older JSON files Shipped
Continue ~/.continue/sessions/ ($CONTINUE_GLOBAL_DIR) JSON Shipped
Aider .aider.chat.history.md in the repository ranwhat runs in, and in your home folder ($AIDER_CHAT_HISTORY_FILE) Text Shipped
Goose ~/.local/share/goose/sessions/ ($GOOSE_PATH_ROOT) SQLite, read only; older JSONL Shipped
Zed ~/.local/share/zed/threads/threads.db ($XDG_DATA_HOME/zed) SQLite, read only Shipped, secrets read-only
Warp ~/.local/state/warp-terminal/warp.sqlite ($XDG_STATE_HOME) SQLite Shipped, secrets read-only
Amazon Q ~/.aws/amazonq/history/chat-history-*.json for the IDE plugins, and the CLI's data.sqlite3 under ~/.local/share/amazon-q ($XDG_DATA_HOME) JSON, read only; SQLite, read only Shipped, secrets read-only
Qwen Code ~/.qwen/projects/<project>/chats/, and older tmp/<hash>/chats/ ($QWEN_RUNTIME_DIR, $QWEN_HOME) JSONL, JSON Shipped
CodeBuddy ~/.codebuddy/projects/ ($CODEBUDDY_CONFIG_DIR) JSONL Shipped
Grok Build ~/.grok/sessions/<folder>/<session>/updates.jsonl ($GROK_HOME) JSONL Shipped
Droid ~/.factory/sessions/ ($FACTORY_HOME_OVERRIDE) JSONL Shipped
Kimi Code ~/.kimi-code/sessions/ ($KIMI_CODE_HOME) JSONL Shipped
Kimi CLI ~/.kimi/sessions/ ($KIMI_SHARE_DIR) JSONL Shipped
Pi ~/.pi/agent/sessions/ ($PI_CODING_AGENT_DIR) JSONL Shipped
Oh My Pi ~/.omp/agent/sessions/ ($PI_CODING_AGENT_DIR, $PI_CONFIG_DIR, $XDG_DATA_HOME/omp) JSONL Shipped
Muse Code ~/.local/share/muse/sessions/ ($XDG_DATA_HOME/muse) JSONL Shipped
Mistral Vibe ~/.vibe/logs/session/ ($VIBE_HOME) JSON, JSONL; unified sessions read only Shipped
DeepSeek Harness ~/.dsh/sessions/ ($DSH_HOME) JSONL, compressed ones read only Shipped
OpenClaw $OPENCLAW_STATE_DIR/agents/*/agent/openclaw-agent.sqlite (default ~/.openclaw) SQLite, tool calls found by shape; compressed events and cold archives not read yet Shipped, secrets read-only
Meta Muse Meta's cloud Nothing on your machine Cloud only
Grok Bot xAI's cloud Nothing on your machine Cloud only
Amp ampcode.com, for the current Amp Nothing on your machine Cloud only

Each agent is read from where it keeps its history, and the variable in brackets moves it for ranwhat as it moves it for the agent. --source ID reads one agent, --path ID=PATH reads one from elsewhere, and ranwhat sources lists where it looked and what it found.

Databases and compressed files are only ever read. Cursor, Zed, Warp and OpenClaw keep their history in SQLite, so clean finds their secrets but cannot mask them there; the same goes for both of Amazon Q's stores, the databases Kilo Code, OpenCode and Goose keep, and Mistral Vibe's unified sessions and DeepSeek Harness's compressed ones. Windsurf keeps Cascade's own history encrypted, so ranwhat counts those files and reads the plaintext transcripts Windsurf's hook writes instead. Not read yet: the large tool outputs Claude Code stores in <session>/tool-results/, and ~/.claude/history.jsonl. Where Claude Code keeps your history lists the files a session leaves behind.

Meta Muse, Grok Bot and the current Amp keep their history in their vendor's cloud, so there is nothing on your machine to read. Muse Code and Grok Build, Meta's and xAI's coding CLIs, are read.

04 / Output

Machine-readable, and one command for both halves.

ranwhat watch --json prints one record per flagged call.

Record id, source, session, project, cwd when the agent wrote one down, timestamp, tool_name, tool_call_id, payload_hash, severity, and every rule the call tripped, each with its evidence.
Its id 16 characters, the same on every run over the same history, and new for a call run again or flagged for something more. A call read twice with no time of its own is one record, with each copy's id in ids. The report prints it at the end of each action's line.
What you expected ranwhat ignore ID stops listing an action you expected, and ranwhat ignore all every action listed now, so later runs list only what is new. Each report says how many it left out and by which line of ~/.ranwhat/ignore, and --no-ignore lists them again. A secret is never left out, a critical action only by its id or a narrow entry that expires, and a change an agent makes to what ranwhat reports only once you acknowledge it.
Once each A call replayed by a resumed session is reported once, not once per transcript that carries it.
Both halves ranwhat check runs watch and clean in one pass, and changes nothing.

Related guides