GUIDE · HOW-TO 9 min ·

Audit what your AI coding agent didGit, shell, logs, filesystem, provider side.

The agent ran for four hours. Now reconstruct what happened. Some sources give you a complete picture; others give you nothing if you weren't already logging.

TL;DR· the answer, in twenty seconds

What: An AI coding agent ran for hours and you need to know what it actually touched. Git, shell history, agent logs, and filesystem timestamps give partial coverage. Network traffic and context-window contents are usually gone.

Fix: Start with git reflog and git log --all, then check ~/.zsh_history, then the agent's own log files. Cross-reference with filesystem timestamps: find . -newer /tmp/before.ts.

Lesson: Most gaps are pre-incident posture failures. If you weren't logging shell timestamps, capturing network traffic, and enabling verbose agent logs before the session, that data doesn't exist now.

The Replit incident in mid-2024 is the reference case. An agent deleted a production database. Recovery required reading agent conversation logs and database transaction logs in parallel to piece together the sequence of events. The two sources disagreed in places. Neither was complete on its own.

You let an agent run. It finished. Now you want to know what it actually did, not just what you asked it to do.

The coverage you get depends almost entirely on what you had running before the session. Some sources are durable and independently verifiable. Others are blank if you weren't already capturing them.

The short version

  • Git is your most reliable source. git reflog shows every ref move; git log --all catches commits on detached heads and orphaned branches.
  • Shell history is partial but often useful. Timestamps exist only if you had HISTTIMEFORMAT (bash) or EXTENDED_HISTORY (zsh) set before the session.
  • Agent logs vary by tool. Claude Code keeps a JSONL conversation log; Aider writes .aider.input.history; Cursor stores diff-based checkpoints.
  • Filesystem timestamps tell you what changed, not why. find . -newer /tmp/before.ts gives you the list if you set a reference point.
  • Network traffic is gone unless you were capturing it. lsof -i shows current connections, not past ones.
  • Provider-side logs (Anthropic console, GitHub audit log, AWS CloudTrail) exist independently of your machine and cover what touched their APIs.

Five sources of evidence

Git

Start here. Git records every commit, but the reflog goes further: it captures every ref move, including branch resets, rebases, and detached-head transitions.

git reflog --all --date=iso

This shows what HEAD pointed to at each moment, with ISO timestamps. An agent that reset a branch, did work, then reset again leaves traces in reflog even if those commits are gone from git log.

To see all commits across all branches, including orphaned ones:

git log --all --oneline --graph --date=iso

Orphaned commits appear if the agent created a branch, committed, then deleted the branch. The reflog retains them for 30 days by default (the gc window).

Check uncommitted changes in the working tree:

git status
git diff HEAD

Uncommitted modifications are only visible here. If the agent wrote to a file and stopped before committing, git diff shows it. Reflog does not.

For projects that require GPG-signed commits, look for unsigned entries:

git log --show-signature

An unsigned commit in a signed-commit project means something outside your normal workflow made it.

Shell history

Shell history surfaces commands the agent ran outside of git-tracked file changes. It is a starting point, not a complete record.

Bash:

cat ~/.bash_history

Zsh:

cat ~/.zsh_history

Fish:

cat ~/.local/share/fish/fish_history

Without HISTTIMEFORMAT set (bash) or setopt EXTENDED_HISTORY (zsh), you have command order but no timestamps. You know the command ran; you don't know when.

Agents can bypass shell history by running commands in a subprocess with history disabled, or by using exec to replace the shell process. Commands run this way won't appear. Use shell history as a starting list, then cross-check against agent logs.

Agent conversation logs

Each tool stores something different. Quality varies.

Claude Code keeps a JSONL conversation log in ~/.claude/projects/<project-hash>/. Each conversation is one file. The log records every user turn, every assistant turn, and every tool call with its result and timestamp. If the agent deleted a file, the tool call appears with the exact path.

ls -lt ~/.claude/projects/

Find the project directory and inspect the most recent .jsonl file:

cat <path-to>.jsonl | jq 'select(.type == "tool_use") | {tool: .name, input: .input, ts: .start_time}'

Aider writes two history files. .aider.input.history in the project directory contains every prompt you typed. ~/.aider.chat.history.md in your home directory holds the full conversation, including aider's responses. Neither is structured like a tool log; read them as a transcript.

Cursor writes diff-based checkpoints to .cursor/ in the project. These snapshots can show intermediate states the agent reverted before committing. If the agent made changes and then undid them before a git commit, checkpoint files may be the only record of those intermediate states.

For hasp users: hasp audit shows every secret grant made during the session, and hasp audit --verify checks the HMAC chain for tampering. If the agent escalated to a credential it shouldn't have touched, the grant record is here.

Filesystem timestamps

Set a reference timestamp before a long agent session:

touch /tmp/agent-session-$(date +%Y%m%dT%H%M%S).ts

After the session:

find . -newer /tmp/agent-session-<timestamp>.ts -not -path './.git/*'

If you forgot to set the reference before the session, use the timestamp from the first entry in the agent's conversation log. Create a proxy file with touch -t <YYYYMMDDhhmm>, then run find against it.

On macOS, mdls provides extended metadata:

mdls -name kMDItemContentModificationDate <filepath>

stat works on both platforms:

stat -f "%Sm %N" -t "%Y-%m-%d %H:%M:%S" <filepath>    # macOS
stat --format="%y %n" <filepath>                        # Linux

Filesystem timestamps are not always accurate. If the agent copied a file and preserved its original modification time, find -newer will miss it. Cross-reference with git commit times and agent log timestamps whenever the sources disagree.

Provider-side logs

These logs live on the provider's infrastructure, independent of your machine. That makes them harder to tamper with and harder to get detail out of.

Anthropic: log into console.anthropic.com and check usage by API key. You'll see token counts by time window. This confirms the agent was active and roughly how much it processed. Content is not exposed.

OpenAI: same pattern at platform.openai.com/usage.

GitHub audit log (org accounts): Settings → Audit log. Filter by date and actor. Pushes, PR opens, and API calls each appear with a timestamp and the authenticated user.

AWS CloudTrail: if the agent had AWS credentials in scope, CloudTrail records every API call. Filter by access key or user-agent. Agents using boto3 or the AWS CLI embed a user-agent string that usually identifies the tool and version.

Your own application logs are worth checking too. Claude Code sends a distinct user-agent header on API calls. If you log request headers, the agent's calls are already in your access logs.

What you can't recover after the fact

Outbound network traffic is gone if you weren't capturing it. lsof -i shows current open connections. Neither lsof nor nettop records past traffic.

If the agent exfiltrated data over HTTPS to an external host, and you had no packet capture or proxy running, you have no payload record. You might find a DNS query in your router logs if you had query logging enabled. You won't find what was in the request body.

The agent's context window is also gone. You can reconstruct what the agent was told from the conversation log, but the log doesn't record what the agent inferred from that context or what it considered doing before choosing a different action. For most post-session reviews this gap doesn't matter. For a security incident where you need to reason about what the agent might have seen and how it might have acted on it, the gap matters.

If an agent read a file containing credentials and then made an outbound connection to an unknown host, you can potentially prove the file read (filesystem access time, agent log tool call) and prove the connection (if you were capturing). What the agent sent is gone. You're reconstructing under incomplete information.

Git doesn't capture everything, and that gap misleads people

The common advice after an unexpected agent session is "check git." That's right but incomplete.

Git captures committed changes. An agent that wrote to disk, tested its work, then reset the branch before you looked leaves no git trace beyond reflog. An agent that modified files outside your project directory leaves no git trace at all. An agent that ran shell commands (curl, psql, aws s3 cp) leaves no git trace even if those commands caused real damage.

The Replit incident happened in a database that git never touched. The git history was clean. The damage was in transaction logs.

Shell scripts the agent wrote and then executed leave evidence in shell history and agent logs, not in git. Files the agent created in /tmp may be gone before you look. Environment variables the agent set in its subshell disappear when the session closes.

Check git first. It's the richest source for code changes. Stop assuming it's the whole picture.

Pre-incident posture: what to enable now

Shell history with timestamps

Add to ~/.zshrc:

setopt EXTENDED_HISTORY
HISTSIZE=50000
SAVEHIST=50000
HISTFILE=~/.zsh_history

For bash, add to ~/.bashrc:

export HISTTIMEFORMAT="%Y-%m-%d %T "
export HISTSIZE=50000
export HISTFILESIZE=50000

Agent verbose logging

For Claude Code, the JSONL conversation log is on by default. Confirm it's accumulating:

ls -lh ~/.claude/projects/

For Aider, pass --verbose. For Cursor, keep checkpoints enabled (the default; don't disable it).

Reference timestamps

At the start of any long agent session:

touch /tmp/agent-session-$(date +%Y%m%dT%H%M%S).ts

One command. Run it before you hand off to the agent. After the session, find . -newer gives you the full file-modification list.

Packet capture

On a dev laptop, periodic tcpdump or PF logging at the firewall gives you network evidence after the fact. Most teams won't accept that overhead. At minimum, enable DNS query logging on your router. DNS queries don't show payload but they show outbound connections by hostname, which is often enough to flag unexpected destinations.

Service audit logs

GitHub audit logs require an org plan. AWS CloudTrail has a per-event cost. Enable them before you need them. If an agent touches either service during an incident, you want the record to exist. You can't retroactively enable CloudTrail and recover events from before you turned it on.

A short checklist for after a long agent session

## Post-agent-session audit

- [ ] git reflog --all --date=iso (check for unexpected ref moves)
- [ ] git log --all --oneline --graph (find orphaned commits)
- [ ] git diff HEAD (uncommitted working tree changes)
- [ ] git log --show-signature (unsigned commits in a signed-commit project)
- [ ] cat ~/.zsh_history (or ~/.bash_history), filter by approximate session time
- [ ] Review agent conversation log (Claude Code: ~/.claude/projects/<hash>/*.jsonl)
- [ ] Review agent input history (Aider: .aider.input.history, ~/.aider.chat.history.md)
- [ ] find . -newer /tmp/session-start.ts (if you set a reference timestamp)
- [ ] Check provider usage logs (Anthropic console, OpenAI dashboard) for token spike
- [ ] Check GitHub audit log for unexpected pushes or API calls
- [ ] Check AWS CloudTrail if agent had AWS credentials in scope
- [ ] Review app access logs for agent user-agent string

What this means for your stack

Most audit gaps are pre-incident posture failures. Shell timestamps weren't on. Packet capture wasn't running. Agent verbose logging was at the default level. That data doesn't exist to recover now. Reconstruction works on what you happened to be collecting before the session started.

The durable improvement is a broker that writes to an append-only audit log as a design requirement, not a logging afterthought. hasp is one working implementation: it keeps a HMAC-chained ~/.hasp/audit.jsonl, and hasp audit --verify lets you confirm the chain is intact after a session. curl -fsSL https://gethasp.com/install.sh | sh, hasp setup, connect a project. Source-available (FCL-1.0), local-first, macOS and Linux, no account.

Outbound network traffic is the one gap that can't be closed after the fact. Set up the capture before the next session, not after.

Sources· cited above, in one place

NEXT STEP~90 seconds

Stop handing the agent your real keys.

hasp keeps secrets in one local encrypted vault, brokers them into the child process at exec, and never lets the agent read the value.

  • Local, encrypted vault — no account, no cloud, no telemetry by default.
  • Brokered run — agent gets a reference, the child process gets the value.
  • Pre-commit + pre-push hooks catch managed values before they ship.
  • Append-only HMAC audit log answers "did the agent touch the prod token?" in seconds.
→ okvault unlocked · binding ./api
→ okgrant once · pid 88421
→ okagent never read

macOS & Linux. Source-available (FCL-1.0, converts to Apache 2.0). No account.

Browse all clusters· eight threads, one index