Since Claude Code 2.1.232 shipped on August 13, 2026, every background agent you run gets its entire transcript re-sent to its own model roughly every 30 seconds, to produce a status line of three to five words. That is the observation behind this article, and it changes what you should audit. If you have been treating the tool-permission list in .claude/agents/ as the data boundary for your background agents, the practical finding is this: the permission list describes what an agent may call, but the transcript records what it already saw, and the transcript is what repeatedly leaves the machine. The audit that matters after deployment is a diff between those two artifacts, and it takes an afternoon, not a quarter.
The boundary shift: from what the agent can call to what it already saw
The mechanism was documented by a practitioner gist from Flamerix AI, tested on Linux across Claude Code versions 2.1.257 through 2.1.312 and updated October 29, 2026:
Every ~30 seconds, for every background agent, Claude Code sends that agent’s entire transcript to the agent’s own model (usually Opus) and asks it to “describe your most recent action in 3-5 words”. The answer only updates the agent’s status line in the agents panel; it never reaches the model or your conversation. There is no setting that turns it off, and since 2.1.232 (August 2026) it has been on by default.
Read that carefully as a data-flow statement. Whatever entered the transcript (every file read, every Bash command’s output, every echoed environment variable) becomes the payload of a recurring outbound API call. The status feature is not a summarization step that distills the transcript down; the summary is produced from the full transcript, on the model side.
This reframes where the review boundary sits. Anthropic’s own platform documentation describes the intended isolation design: “Claude delegates to other agents, each with its own independent context window.” An independent context window is not a data filter. An independent source-level analysis of Claude Code (pinned to v2.1.88, an important caveat I will return to) describes what gets packed into each model call:
Before the model is called, the agent loop assembles a context window from the tool pool (Section 6), CLAUDE.md files, auto memory, and conversation history.
So the outbound surface of a background agent is not its tool list. It is the union of its tool results, CLAUDE.md content, auto memory, and conversation history, all of which accumulate in the transcript. Tool permissions still matter, but as the upstream control on what enters the transcript, not as the boundary themselves. The permission gate decides what gets in; the transcript decides what goes out. Once something is in, it rides every subsequent summary call.
I want to be precise about epistemic status here. The 30-second mechanism rests primarily on one practitioner’s telemetry, corroborated by a second-hand macOS static check (reported in the gist via HN commenter lostsock on October 29, 2026) that confirmed the prompt text and timer exist in the binary but did not verify token counts. Anthropic’s Claude Code background-agents documentation was not in the fetched evidence set, so whether Anthropic considers full-transcript status calls intended behavior or a defect is an open question. The audit procedure below is sound either way, because it works from artifacts you control rather than from claims about internals.
Step 1: Locate the transcript
Claude Code stores per-project session transcripts as JSONL files under ~/.claude/projects/**/*.jsonl. This is documented in practice by the sysmon-widget project, whose monitor agent is described as “a single-file, stdlib-only Python HTTP server. GET /stats returns a JSON snapshot: RAM used/total, storage used/total for /, and Claude Code token usage aggregated from every ~/.claude/projects/**/*.jsonl transcript on that machine, both for today and for a rolling 7-day window.”
That project demonstrates two things useful here. First, the transcripts are plain, readable JSONL: you do not need special tooling to enumerate them. Second, per-machine aggregation across all transcripts is already a solved, small problem. If your team runs background agents across several developer machines, the audit unit is the machine (or the repo checkout), not the vendor console.
One caution the sysmon-widget README illustrates by example: it serves those stats unauthenticated on the LAN. A monitoring endpoint built on transcript data can itself leak the data you are auditing. If you stand up aggregation as part of this check, bind it to localhost or put it behind auth.
Step 2: Enumerate what entered the transcript
The source-level analysis gives you the enumeration checklist directly: tool results, CLAUDE.md files, auto memory, conversation history. For a background agent, the rows that matter most in practice:
- File reads. Every Read tool result is in the transcript verbatim. If the agent read a file containing secrets, a customer export, or a proprietary algorithm, that content is now recurring outbound context.
- Bash output. This is the least predictable row. A
cat .envrun for debugging, agrep -racross a config directory, acurlthat returns an auth header: all of it lands in the transcript as tool output, regardless of whether it was relevant to the task. - CLAUDE.md. This one is structural, not incidental. Per an analysis of Claude Code project configuration: “For each request, Claude first reads the content of this file looking for information that can help it at fulfilling the request.” CLAUDE.md is a standing passenger on every call. If your CLAUDE.md names internal hosts, ticket systems, or architecture details, it ships with every summary call too.
- Auto memory and conversation history. Whatever the agent accumulated across the session is part of the payload.
The enumeration is mechanical: parse the JSONL, list every tool result by type and source, and note CLAUDE.md and memory entries. What you are building is the actual outbound-content inventory, per agent.
Step 3: Diff against the scope you intended
The artifact you diff against already exists in your repo. Research on multi-agent Claude Code setups documents that subagent profiles “reside in the repository under a .claude/agents/ directory; Claude Code automatically loads them so that the orchestrator can invoke any agent by name when needed,” each with an explicit tool list such as file read/write, edit, and bash access.
The diff question is not “did the agent exceed its permissions?” It presumably did not; the tool list was enforced. The question is “did the consequences of the permitted calls exceed the outbound context I intended?” A Read grant scoped to src/** is narrow until you discover a secrets file checked into src/config/. A Bash grant is a Read grant over everything the shell can reach.
The security literature gives this gap a name. Work on dynamic capability scoping frames it as follows:
The envelope reflects what the role might ever need, not what any individual task actually requires. We call this gap context-privilege mismatch. Preemptively deploying the permissions creates an unnecessary attack surface.
The same work notes that read operations are the exfiltration-relevant half of a permission, while writes create persistence and impersonation risk. For a transcript audit, reads and Bash output dominate, because exfiltration here is not an attacker carrying data out; it is the normal operation of the status-summary mechanism re-sending whatever was read. And a review of 21 agent-permission systems found that nearly all of them “treat the adversary as agent misbehavior due to prompt injection or hallucination” and assume a benign provider, with continuous post-deployment permission control being rare. That is precisely the assumption this audit does not make. You are not checking whether the agent misbehaved; you are checking what normal behavior already shipped.
When the diff shows a mismatch, there is also policy-level guidance on what a safe tightening looks like. An empirical evaluation of task-based permission scoping argues that permission combinations are safe to prohibit when no legitimate task requires them together: “Reading an uploaded file and outbound HTTP call is not required in combination by any department based on the policy document and the generated task dataset.” Applied here: if no legitimate task for your test-runner agent requires reading files outside tests/**, the Read scope should say so, because every permitted read is an outbound read.
Step 4: Cross-check the OpenTelemetry export
A disk-only audit has a structural hole, and the gist documents it directly:
Cost tools that read transcripts don’t see it. These requests are not written to the session logs on disk (#104358); only the OpenTelemetry export shows them.
The agent_summary calls themselves, the recurring calls that carry the transcript, do not appear in the JSONL session logs. The gist author found them by grouping claude_code.api_request OpenTelemetry events by query_source, which surfaced agent_summary as a distinct stream, reportedly costing more than the main conversation itself in that team’s telemetry.
So the audit has two mandatory channels:
| Channel | What it shows | What it misses |
|---|---|---|
On-disk JSONL under ~/.claude/projects/**/*.jsonl | Full transcript contents: file reads, Bash output, CLAUDE.md, memory; daily and 7-day token totals per machine | The agent_summary requests themselves (absent per issue #104358) |
OpenTelemetry export (claude_code.api_request grouped by query_source) | The ~30-second agent_summary calls, their frequency, their token weight | Nothing identified in the evidence, but requires export to be enabled |
Without the second channel, your token totals understate API traffic, and you cannot verify how often the transcript actually went out. Enabling the OpenTelemetry export is therefore not optional instrumentation; it is the only way to see the mechanism you are auditing.
Two reproduction notes from the gist matter if you want to observe this live. Headless claude -p runs do not arm the summary timer by default; the default-on behavior occurs in interactive sessions with background agents. And for live tests the gist sets CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES=1. If your repro attempt shows nothing, check the session type before concluding the mechanism is absent.
Gating: tighten per-agent scopes, or pull the kill switch
Once the diff is in hand, the decision is keep, tighten, or disable.
Tighten when transcript contents exceed intended outbound context but the agents are earning their keep. This means editing the per-agent tool lists in .claude/agents/: narrowing Read paths, removing Bash from agents whose tasks do not require shell access, and scrubbing CLAUDE.md of standing detail that does not need to ride every request. The context-privilege-mismatch framing supplies the principle: scope to what the task requires, not what the role might ever need.
Disable is coarser than you probably want, and the gist is blunt about why:
CLAUDE_CODE_FORK_SUBAGENT=0 and CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 do stop it, but only by taking fork subagents or background agents with it.
There is reportedly no clean off switch for the summary calls alone: the SDK option agentProgressSummaries defaults to false yet, per the gist, cannot actually disable anything. CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 is a kill switch that removes the feature, not a tuning knob.
The gist also ships a Bun preload that patches the client to suppress the summary calls. I would not treat that as a recommendation. The gist itself warns the preload may conflict with Anthropic’s terms and that a Claude Code update can silently undo it, which means a team relying on it has both a compliance question and a regression risk on every upgrade. It is a workaround for individual experimentation, not a control.
My judgment on sequencing: run the audit before you touch anything. If the diff is clean, meaning the transcripts contain only what you would have sent to the model anyway, the status mechanism adds cost but not new exposure, and you can decide on cost grounds separately. If the diff shows secrets, customer data, or broad Bash output in the transcript, tightening the scope is the fix with the best evidence behind it, because it reduces what enters the transcript at the source. The kill switch is for the case where you cannot bound what background agents touch and cannot afford to find out gradually.
Version matrix: 2.1.232 through 2.1.312
The defaults and switches have moved quickly, and every row below is per the gist’s version timeline, so treat it as practitioner-observed rather than vendor-documented:
| Version | Date | Change |
|---|---|---|
| 2.1.232 | Aug 13, 2026 | Whole-transcript summary calls become default-on for interactive background agents |
| 2.1.233 | (picked up in gist telemetry) | Gist author’s weekly agent_summary spend share jumps from 3.5–7% to 7.3%, then 11.8% |
| 2.1.300 | Oct 14, 2026 | Summary interval becomes server-tunable, 30–240 s |
| 2.1.310 | Oct 23, 2026 | “Short mode” ships: ~2k tokens of notes instead of full transcript, optionally written by a smaller model, but off by default and changeable only via server flags |
| 2.1.312 | (tested) | First independent macOS static confirmation (lostsock, HN, Oct 29); token numbers not verified there |
Two rows deserve skepticism markers. The spend-share figures (3.5–7% in July, rising to about 16% by mid-October) are one team’s telemetry and version mix; they say something real about that team’s exposure trajectory and nothing reliable about yours, which is why this article makes no cost-multiplier claim. Research on token consumption in agentic coding supports the general shape (agentic coding costs are dominated by input tokens, and models systematically underestimate their own usage), which is an argument for measuring your own traffic rather than adopting anyone’s percentage. The gist’s separate “~15–20% of tokens” headline carries the same single-team caveat.
Short mode is the row to watch. If it becomes default-on in a future release, the exposure calculus changes from “full transcript every 30 seconds” to “notes every interval,” but the audit procedure does not change: whatever the payload, the transcript is still the inventory of what the agent saw, and the diff against intended scope is still the gate. Re-verify these version-specific claims after each release; the gist’s own timeline shows the behavior shifting three times in ten weeks.
What this evidence does not establish
Being honest about the limits is what makes the procedure worth trusting:
- Prevalence. The mechanism is documented by one practitioner’s OpenTelemetry telemetry on Linux (versions 2.1.257–2.1.312) plus one second-hand macOS static check that did not verify token numbers. That is enough to justify an afternoon audit, not enough to generalize about every installation.
- Intent. Whether Anthropic treats full-transcript status calls as designed behavior or a defect is unsettled. The vendor’s platform page confirms independent context windows per delegated agent but says nothing about this call path. Notably, the gist observes the status calls going to the agent’s own model (usually Opus) with the full transcript, while Agent View’s row summaries are documented as a Haiku-class model refreshing every few minutes; those appear to be two different mechanisms, and conflating them would be a mistake.
- Assembly details. The source-level analysis is pinned to v2.1.88, which predates the 2.1.232 default-on. It establishes how context is assembled in general (tool pool, CLAUDE.md, auto memory, history), which grounds the enumeration checklist, but it cannot confirm or refute the summary call path itself.
- Completeness of the disk channel. The JSONL transcripts demonstrably omit the agent_summary requests, so they are not a complete record of what reached the API. The two-channel audit exists because neither channel is sufficient alone.
None of these gaps block the recommendation. Locate the transcripts, enumerate what entered them, diff against the .claude/agents/ scopes you wrote, and confirm the frequency through the OpenTelemetry export before you decide. The permission list was never the boundary; the transcript is. Now you can read it.
Frequently Asked Questions
Where are Claude Code session transcripts stored on disk?
Claude Code stores per-project session transcripts as JSONL files under ~/.claude/projects/**/*.jsonl.
How can I see the agent_summary API calls that are missing from disk logs?
The gist author found them by grouping claude_code.api_request OpenTelemetry events by query_source, which surfaced agent_summary as a distinct stream, reportedly costing more than the main conversation itself in that team’s telemetry.
Can I disable just the background agent summary calls without stopping the agents?
There is reportedly no clean off switch for the summary calls alone: the SDK option agentProgressSummaries defaults to false yet, per the gist, cannot actually disable anything. CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 is a kill switch that removes the feature, not a tuning knob.

Join the discussion
Share a useful perspective or ask a question about this article.