Engineering · Investigation · Meridian
▖ Case File · MRDN-CON-004 Meridian · Tradewind · July 2026 · Claude & Codex · Agent Continuity

Real AgentPM case, shared with permission — organization and application names changed to protect the innocent.

A narrated investigation

Following the agents

A routine review of AI coding agent activity uncovered something unexpected. The code was in GitHub. The story of how it got there wasn't.

AgentPM Engineering 12 min read Subjects: Claude · Codex System: Tradewind

The engineering team was using AI coding agents to build an automated trading platform. With a small team, the agents were doing most of the engineering work.

At the end of the week, the CTO opened AgentPM for a routine review of the previous week's agent activity. The goal was simple: understand what had changed and verify that everything looked as expected.

It didn't.

What started as a routine review quickly became a security investigation.

The platform had been built across Claude and Codex, working from different machines and committing directly to the repository. GitHub showed the final result, but not the conversations, decisions, or unfinished work that led there.

So instead of starting with the code, we started with the agent history.

This is that investigation, in the order it happened.


Question 01

What have the agents actually been doing?

Not the commits — the activity. Which machines, which agents, how much work, at what cost. Before drilling into any one session we wanted the shape of the week. The org's home dashboard answers this without a query.

agentpm.dev/o/Meridian
Health & Admin dashboard.
The week at a glance. AgentPM shows recent agent activity by directory, then rolls that activity up into utilization by agent and model. In one view, the CTO could see where work happened, how much agent activity ran, and which projects deserved a closer look.

The dashboard tells us the fleet is real and busy, but not what it's pointed at. For that we drop to the CLI — the same read-only agentpm API the agents themselves use — and ask for the project rollup.

~/src — bash
$ agentpm conv projects --org Meridian
40 projects · 1,391 conversations · 339,344 turns · 9.1B in / 23M out

  /home/dev/src/app-core        claude        700 conv   96K turns   1.6B in
  /Users/dev/…/app-core          codex          32 conv   34K turns   1.3B in
  /Users/dev/…/ops-dashboard     claude+codex   42 conv   46K turns   2B in
  /Users/dev/…/agent-tools       claude+codex   63 conv   42K turns   1.6B in
  … 36 more

The project rollup turns a week of scattered agent activity into a review map. It shows which directories were active, which agents worked there, how many conversations and turns accumulated, and where token volume clustered. Instead of guessing which chat history mattered, the CTO could narrow the review to the highest-signal projects first.

Question 02

Did the agents touch anything risky?

On a trading system, "risky" has a specific meaning: credentials, live orders, auth. We didn't know which conversation to open, so we narrowed the search to the trading-platform project and asked AgentPM for conversations involving secrets, credentials, API keys, and related work.

~/src — bash
$ agentpm conv search "secret credential api key" --cwd /home/will/src/Tradewind
4 conversation(s) for the project

  goc_5139acbc19e3f720956f8db1  Execution-issue report published after log review        claude  512t
  goc_8f38b62e9d5a2dc83c1f980e  Execution log triage and May 20 report publication       claude  512t
  goc_43591a3b03a873404d5ab72d  Investigate execution warnings and publish May 20 report claude  369t
  goc_48fe9d63abab27c950eca5df  Norgate dump transfer, storage move, and backtest parity claude  15K t
agentpm.dev/o/Meridian/conversations?q=secret credential api key
Project-scoped conversation search for security-related agent work.
One query, eleven conversations. A search of the org’s history for credential, API, and execution-risk terms returns the short list of sessions where they actually appear — including the ones where credentials were reviewed and hardened. The review starts from evidence, not from opening 730 conversations by hand.

The list gave the investigation a path. One thread was a long-running build session where credentials appeared in the open. The shorter report sessions showed the same project being reviewed later for execution issues and safety concerns. We opened the source conversation first, then used the shorter review threads to check what had been noticed afterward.

Question 03

What happened?

We narrowed to the review conversation and asked it to surface just the danger. The find verb searches inside a single conversation and reports the turns where terms converge.

~/src/agent-pm-skill-lookup — bash
$ agentpm conv find goc_63101905ed70d0c1b4ccebb3 "dangerous flagged"
strict turn hit → turn 68 (CLAUDE · concluded)
3 findings, each cited to a source conversation + turn range
…/conversations/goc_63101905ed70d0c1b4ccebb3#notebook:turn-49
Screenshot · Fig. 3 The flagged list. The agent's answer to "have there been any dangerous things flagged in these conversations?" — three items ranked by severity, each tied to the originating conversation and turn range, with resolution status where it could be traced. Account balances and the host are redacted. The flagged list.
Three findings, each with a citation. This is the difference between a chat log and an evidence layer: every claim points to a conversation ID and a turn you can open. The most serious one didn't happen in this conversation at all — it happened days earlier, in a 7,212-turn Codex session.

The headline finding was blunt: a production admin token had been compiled into the front-end JavaScript bundle. We followed its citation straight to the source.

Question 04

Why did it happen?

The citation pointed to conversation goc_71ec…, turns 646–689. We jumped directly to the turn — no scrolling through seven thousand.

~/src/agent-pm-skill-lookup — bash
$ agentpm conv show --turn 655 goc_71ec51d033ff81398744ae6a
[655] assistant
  "the compiled JS literally contains the god token …
   a leaked public env token in the browser bundle."
$ agentpm conv show --turn 646 goc_71ec51d033ff81398744ae6a
[646] assistant
  "If the client bundle includes NEXT_PUBLIC_AUTH_TOKEN,
   every browser effectively carries the god API key."
…/conversations/goc_71ec51d033ff81398744ae6a#notebook:turn-646
Screenshot · Fig. 4 The leak, in context. Capture the Notebook around turns 646–689 in the 7,212-turn session — the agent identifying NEXT_PUBLIC_AUTH_TOKEN in the compiled bundle — plus the conversation header showing its size ($233, 7,212 turns) to convey the haystack this needle sat in. The leak, in context.
Root cause, in the agent's own words. The NEXT_PUBLIC_ prefix inlines a value into the browser bundle. So a single environment variable turned an admin key into public knowledge. This is the reasoning GitHub never captured — and it's sitting at turn 646 of a session no human would ever have scrolled to by hand.

"If the client bundle includes NEXT_PUBLIC_AUTH_TOKEN, every browser effectively carries the god API key."

goc_71ec51d033ff81398744ae6a · turn 646 — verbatim

We had the what and the why. But an agent claiming it fixed something is not the same as it being fixed. The next question was the one an auditor actually cares about.

Question 05

What changed — and did it stick?

The remediation happened in a separate session, goc_b6109… — "Broker-secret encryption implemented and deployed." We asked for its mutating git operations only, to skip the narration and see the actions.

~/src/tradewind — exec (git inspection, remote, read-only)
$ agentpm conv git goc_b6109e169415797ffdf3fe3d --mutating-only
# the agent had run, live, on the production host:
dev@tradewind$ ssh dev@host-b 'cd ~/src/Tradewind \
   && git rev-parse --short HEAD && git rev-parse --short origin/main \
   && git status --short -- apps/api-v2/app/auth.py apps/api-v2/app/security'
head=ba9a213
origin_main=ba9a213
 M apps/api-v2/app/auth.py
 M apps/api-v2/tests/test_broker_secret_storage.py

Read quickly, head == origin_main looks reassuring — in sync. But the security files were modified and uncommitted. The fix was running on the server and existed nowhere in the repository. A live behavior probe confirmed the protection was actually up:

~/src/tradewind — exec (inline probe, remote)
dev@tradewind$ ssh dev@host-b 'curl -s -o /dev/null -w "%{http_code}" :8001/ ; …'
api_root=200
admin_chat_unauth=401
expired_session_rejected=True
forged_clerk_rejected=True
…/conversations/goc_b6109e169415797ffdf3fe3d#notebook:turn-743
Screenshot · Fig. 5 "Deployed: yes. In main: no." Capture turns 744–750: the SSH git-inspection exec block (head=ba9a213 / origin_main=ba9a213 with the M uncommitted auth files) and the four-word conclusion at turn 750. "Deployed: yes. In main: no."
The drift only a two-truths check reveals. A repo audit would have said "still vulnerable." A server snapshot would have said "safe." Both wrong. The agent, prompted by a plain "is it deployed and in main?", checked each separately and refused to conflate them.

"Deployed: yes. In main: no."

goc_b6109e169415797ffdf3fe3d · turn 750 — verbatim

One git checkout . or a fresh clone would have silently reverted the entire security hardening. It was caught, and a few turns later — after the human said "lets commit" — resolved: "Done. It's now deployed and in main." Which raised the question of who was making these calls, and why the design looked the way it did.

Question 06

Who decided this?

The hardening didn't start with code. It started with a question from the human operator, preserved at turn 2 of the encryption session — typos and all, which is part of why it reads as real:

"if we are toring tokens to auth brokerage accounts how to we majke sure to ahve the upmost security"

goc_b6109e169415797ffdf3fe3d · turn 2 — the human, verbatim

The agent's answer is where the decision was actually made. It compared the stated posture to the real storage and found the gap:

…/conversations/goc_b6109e169415797ffdf3fe3d#notebook:turn-2
Screenshot · Fig. 6 The decision point. Capture the turn-2 question and the Codex turn-33 conclusion citing trade_accounts.py:35 (secret stripped from browser responses) versus daily_db.py:127 (a plain TEXT column) — with the line "That is not 'utmost security' yet." The decision point.
Reasoning, not just a diff. The Notebook preserves the decision as it was made: the agent found the storage contradicted the UI's promise, named the file and line, and set the bar for the fix. This is the "why we chose encryption" that a commit message would flatten to "encrypt secrets."

So the chain was human intent → agent audit → a concrete standard → implementation → deployment → the commit-drift catch. Every link visible, every link cited. Which left the question every handoff eventually hits.

Question 07

Was anything left unfinished?

We asked AgentPM for the recent work on the trading checkout, across every agent, and looked for threads that ended parked rather than done.

~/src/Tradewind — bash
$ agentpm conv work --cwd ~/src/Tradewind
  goc_898a03759d668de5176fbaca  codex   Live trade health check & broker-truth reconciliation
  goc_188a315c49bfb3fc6b0d67fd  codex   the brokerage / Schwab integration — parked, not broken

$ agentpm conv show --turn 1 --json goc_188a315c49bfb3fc6b0d67fd
{
  "ok": true,
  "agent_id": "agt_f3cbac5443b9944c1d23861e",
  "org": "Meridian",
  "conversation": {
    "id": "goc_188a315c49bfb3fc6b0d67fd",
    "title": "…look into plugging in the brokerage and Schwab accounts…"
  }
}

There it was: the brokerage integration, parked. Not broken — the thread simply ended mid-effort, the paper account left needing a reset. In a normal workflow that context dies with the session. The obvious next move was to test whether it actually had to.

The real risk of agent work

Unfinished work isn't rare — it's the default. Agents stop when context runs out, when a human steps away, when a task turns out bigger than a session. The question isn't whether work gets parked. It's whether the next agent can find it.

Question 08

Can another agent continue the work?

We didn't have to hypothesize; it had already happened. On July 7, an engineer asked a fresh Claude agent to pick up work a Codex session had been driving the day before — the integration with the trading platform's brokerage:

developer → coding agent (Claude)
you ▸ lets continue work on the Tradewind trading platform, lets check
      agentpm to see where we left off on the brokerage
      integration from yesterday on codex

agent ▸ loading skill: agentpm-conversations …
$ agentpm conv work --cwd ~/src/Tradewind
$ agentpm conv find goc_898a03759d668de5176fbaca "the brokerage remaining next"

agent ▸ Here's where things stand with the brokerage integration on Tradewind:
  • Prior work was Codex, yesterday — reconciliation shipped
  • Open: live-order gating still behind automation_enabled
  • Parked: the brokerage paper account (goc_188a…) needs a reset
  • Resuming there — not from scratch.
…/conversations/goc_6c5d7affd44aa0ba1f06d043#notebook:turn-0
Screenshot · Fig. 7 A cross-agent handoff that worked. Capture turn 0 (the developer's request to "check agentpm… from yesterday on codex") and the expanded turn-31 answer, "the brokerage Integration — Current State." A real Claude session, dated 2026-07-07. A cross-agent handoff that worked.
Claude picking up where Codex left off. Different agent, different vendor, next day, zero re-explanation. The new agent reconstructed the state of the work from the shared record and resumed. This is organizational memory that outlives the session that created it.

"lets check agentpm to see where we left off on the brokerage integration from yesterday on codex."

goc_6c5d7affd44aa0ba1f06d043 · turn 0 — verbatim

The new agent didn't reconstruct that state from memory or from GitHub; it read the prior Codex session out of the shared record and resumed from the known point. One more question remained.

Question 09

What patterns do we see across the organization?

Individual conversations tell you what happened once. To see how the org works, AgentPM reads across all of them. The dashboard's coaching band is the aggregate of 1,400 analyzed sessions.

agentpm.dev/o/Meridian
Screenshot · Fig. 8 Coaching & resource usage. The same read across every session, not one. The coaching band tallies what recurs — 138 sessions that started significant work without a plan, 85 that ran too long to stay efficient, 30 corrections repeated often enough to codify — plus skills the agents could have used but didn't. Below it, where the tokens actually go: exec_command alone ran 41K times for 1.6B tokens. Coaching & resource usage.
340,000 turns, distilled into things to fix on Monday. Eighty-five sessions ran too long to be efficient. A hundred-plus started coding with no plan. Thirty corrections recur often enough to belong in a CLAUDE.md. None of this is visible in any single conversation — only in the aggregate.

The coaching view named the class of problem the earlier questions had been circling one instance at a time. The god token, the commit drift, and the parked brokerage work share a signature: long, unsegmented sessions doing high-stakes work at speed. The evidence supports that reading; on its own it does not establish cause.

Where the investigation landed

We started asking what the agents did last week. Nine questions later we understood an entire engineering effort: a credential leak and its root cause, a security fix that nearly reverted itself, the human intent behind the design, the work left parked, the agent that resumed it, and the organizational habit underneath all of it.

Not one of those answers came from GitHub. Every one came from the conversations.


So what does the org do Monday?

An investigation that only explains the past is a parlor trick. This one came with a to-do list — because the same coaching pass that counted the anti-patterns also named the fixes, and it read across 1,400 sessions instead of one. The fixes are unglamorous, which is usually how you can tell they're the real ones.

What the aggregate says to fix

138 — significant work started with no plan on record. Put a planning step before the first edit.
85 — sessions long enough to lose the thread. Segment and checkpoint instead of running one unbroken marathon.
30 — corrections repeated often enough to belong in CLAUDE.md. Write each one down once so nobody re-types it.

That's the quiet case for keeping a record over coding agents at all. They make the team faster and make the story of why the software is the way it is more fragile — because the author is a process that forgets. The record has to live somewhere that doesn't. The trading platform was fine in the end: the token rotated, the fix committed, the parked work resumed. What would not have been fine was learning any of it by accident, weeks later, from a stranger's browser holding an admin key. That difference wasn't a smarter agent — it was a record you could ask questions of.

You don't need to know where something happened. You ask AgentPM, and follow the answer to the next question.