# Peek

> Read another agent session's transcript straight from its log on disk, with zero footprint on the observed session, and list which sessions are running right now. Covers Claude Code, Codex and the Antigravity CLI (agy/Gemini), and the T3 Code threads wrapped around any of them. Use before sending a message to another session, when observing or coaching a session that must stay untouched, when asked which T3 threads are still open or unsettled, or when asked to peek at, read, or follow what another session is doing.

- Skill: `thatmike1/peek` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add thatmike1/peek`
- Raw SKILL.md: https://api.skillmd.com/api/skills/thatmike1/peek/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: thatmike1 (https://skillmd.com/u/thatmike1)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/thatmike1/peek

---


# peek

Every Claude Code session writes its transcript to `~/.claude/projects/` as it
goes, every Codex session writes a rollout to
`~/.codex/sessions/YYYY/MM/DD/`, and every Antigravity CLI conversation writes
one to `~/.gemini/antigravity-cli/brain/<id>/`. Reading any of them is invisible to the
session that owns it: no turn spent, no context consumed, nothing in its
history. That makes peeking the cheap way to know what another session is doing
before you touch it.

## Commands

```bash
node <skill-dir>/scripts/peek.mjs live                        # sessions running right now
node <skill-dir>/scripts/peek.mjs t3 [--all]                  # open T3 Code threads
node <skill-dir>/scripts/peek.mjs <session-id> --last 6       # the last six messages
node <skill-dir>/scripts/peek.mjs <session-id> --since N      # only what happened since cursor N
node <skill-dir>/scripts/peek.mjs list [projectFilter] [-n 15] # recent sessions on disk, live or dead
```

`live` prints every running session oldest first: project, harness, start time,
how long it has been quiet, pid, session id, title, and the last thing each side
said. It is Linux-only. `list` is the wrong tool for "what is open" because it
returns this morning's dead sessions too; use it to find a session that has
already ended.

`live` and `list` cover all three harnesses and tag each row `cc`, `agy` or
`codex`. `--cc`, `--agy` and `--codex` narrow them to one. A session id is
enough on its own — `peek.mjs <id>` works out which harness it belongs to.

Every render ends with `# next: --since N`. Pass that back on the next call and
you get only the new messages, which is how you follow a session over time
without re-reading it. `--thinking` adds the model's thinking blocks;
`--max 0` lifts the per-message truncation. A Codex row shows the model from
the rollout's turn context, so a warden on Astra reads `codex gpt-6-astra`.

## T3 Code threads

T3 Code is a front end, not a third harness: every thread it opens runs an
ordinary Claude Code or Antigravity session underneath, which is why its rows
reach `live` looking like any other session. A `live` row that belongs to one is
tagged `cc t3`, `codex t3` or `agy t3` and carries a `t3:` line with the thread's own title,
whether it is `busy`, `waiting` on the user or `idle`, and whether it is
settled. It carries no resume handle, because a thread with a live process is
already open; resuming is what the `t3` roster below is for.

`peek.mjs t3` is the separate roster, because a thread outlives its process:
`live` answers what is running, `t3` answers what is still open. Settled threads
are hidden and that is the point of the command — settled is the one state on
that board the user produced deliberately, it only ever accumulates, and what
is left is the set of loops still on them. Snoozed and archived threads are
parked by the same act and go with it; `--all` brings all three back.

## Peek before you message

`SendMessage` to another session costs that session a turn, and an uninformed
message costs two: it asks, waits for the reply, then instructs. Peek first and
send one message that already knows where the session is. The `live` output
carries the session id; `ListAgents` carries the `SendMessage` name and reports
start age rather than id, so pair the two lists per project in start order.
`ListAgents` covers Claude Code only — an agy or codex session is peeked, not
messaged.

## Coach and driver

When one session must stay clean (a recorded demo, a submission transcript, a
benchmark run), do the thinking in a second session that peeks the first. The
driver's transcript then holds only its own work; the coach's guidance never
appears in it.

## What the transcript does not show

The log trails the live turn: you see the last written entries, not the
response being generated. Good enough for steering, too slow for real-time
interruption.

For Claude Code, tool results are not rendered, only tool calls with their
inputs; read the raw JSONL when a result matters. Antigravity and Codex log
each result as its own step, so peek shows them, prefixed `←`, and
`--no-results` drops them. `--no-tools` drops calls and results together, for
any harness, when only the conversation matters. Codex reasoning is encrypted
on disk; `--thinking` shows the summaries, which is all there is.

## How each harness is found

Claude Code: `/proc` for `claude` processes. A process started with `--resume`
names its session in its own argv and is read straight off it; anything else is
joined to `~/.claude/session-env/` by start time within 15s. The argv path is
what makes T3 rows resolvable at all, because T3 restarts the underlying process
every turn and resumes it, leaving the session-env dir stamped whenever the
thread first opened. That dir's SessionStart hook file holds the real transcript
path, which matters because a `--resume` session's dir name points at a jsonl
that does not exist.

Codex: `/proc` for `codex` processes. A running Codex that holds its rollout
file open is joined exactly through its file descriptors, one row per open
rollout; otherwise `codex resume <id>` names the session on argv, and the last
resort is a start-time match against the meta timestamps of the last two days
of rollouts. The rollout is `sessions/YYYY/MM/DD/rollout-<stamp>-<id>.jsonl`,
found by the id in its name, and the title comes from
`~/.codex/session_index.jsonl` when Codex has named the thread. `list` walks
the last 45 days of rollouts, so an older session resumed today is out of its
reach.

T3 Code: `~/.t3/userdata/state.sqlite`, read-only, joining
`provider_session_runtime` to `projection_threads`. The underlying session id
lives in `resume_cursor_json` under a per-provider key — `resume` for Claude
Code, `threadId` for Codex, `sessionId` for Antigravity — and that field is
the only join between a thread and its session. A T3 process is also recognisable before its state row
lands, because T3 gives every session it starts an MCP server named `t3-code`,
which shows in the process's argv.

Antigravity: `/proc` for `agy` processes, each of which holds an open file
descriptor on `~/.gemini/antigravity-cli/presence/<conversation-id>.lock` for
its whole life. That is an exact process-to-conversation join, not a
heuristic. The transcript is
`brain/<id>/.system_generated/logs/transcript_full.jsonl`, the title is
`annotations/<id>.pbtxt`, and the workspace comes out of the metadata blob in
`conversations/<id>.db`. `conversation_summaries.db` looks like the obvious
index and is not — on this machine it stopped being written on 31 August 2026.

