docs(mcp): disclose what read_chat/list_chats drop and point at the raw JSONL (#615) - #625
Conversation
…aw JSONL (#615) The self-MCP read tools describe what they return but not what they silently discard, so callers use `read_chat` for analysis it cannot support and trust the result. `read_chat` renders every tool call as a `role: "tool"` entry with EMPTY text — no name, no input, no output — and those blanks still spend the caller's `limit`. On a real agentic transcript they are the majority of the payload. Thinking blocks, attachments and sub-agent transcripts are dropped outright. None of that was written down anywhere, in the tool description or the public reference. Consequences observed on the nightly Night-Watch reviewer: it reported "no API errors, crashes, stalls or loops" for a window in which the chats it read held 31 is_error tool results, because that is precisely the class of record this path deletes. It also mistyped one session id, got `total: 0` and no error back, and published "1 empty child-worktree chat" about a 1.5 MB conversation it never opened. - `READ_CHAT_DESC`: state the blank-tool behaviour and that it consumes `limit`; name what else is dropped; say the tool answers "what is this chat about / what was decided" and NOT "how did this chat go"; give the transcript path (incl. sub-agents) for the lossless view; warn that an unknown session_id means NOT FOUND, not "empty chat". - `LIST_CHATS_DESC`: say `name` degrades to an 8-char sessionId prefix, that this means untitled, and that it is not a usable id. - Mirror both in the public reference page, which had the same gap — it listed `tool` as a role without saying those entries are empty. - Pin the disclosures with a unit test; verified it fails without the description change rather than passing vacuously. Descriptions and docs only — no behaviour change. The underlying fidelity defect is #613 and the naming defect is #614; this makes the current behaviour honest in the meantime. Co-Authored-By: Claude <noreply@anthropic.com>
Deploying paddock with
|
| Latest commit: |
5d59081
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://b37c1a9a.paddock-7u2.pages.dev |
| Branch Preview URL: | https://fix-615-mcp-read-tool-descri.paddock-7u2.pages.dev |
|
The overlap is textual, in two hunks — whichever of us merges second will need to resolve it:
No opinion on merge order from me; they're independent and both small. Flagging it so whoever hits the conflict knows the intended end state rather than picking a side. |
|
Correction — no conflict after all. #580 merged as Actually computing it (
GitHub agrees: this PR still reads |
…rt (#633) * chore(docs): start v0.54/v0.55 docs pass * docs(website): What's New entries for 0.54 and 0.55 0.55 leads on importing existing Claude Code CLI chats (#621) — the release's headline — plus the health-path auth fix (#579, which carries an operator action), the two measured memory fixes (#602), the sub-agent bar rehydration fix (#623) and the self-MCP honesty and root-workspace work (#625, #580). 0.54 leads on retiring the 'keeper' persona for Claude (#598), with the breaking env/config rename in a table, and Home leading with running then unread chats (#607) — noting that this is what fixed the in-flight badge gap the 0.53 entry describes. Also the foreground sub-agent duplication fix (#595), the live sub-agent bar (#605) and the sweeper working-directory fix (#581). Frontmatter description and the editorial arc paragraph updated: the new arc is Paddock ceasing to be a walled garden. * docs(website): a recorded demo of chat import, plus two screenshots Converts whats-new.md to .mdx so it can use the repo's own DemoVideo component, which is built for exactly this: an MP4 configured to behave like a GIF (muted/autoplay/loop) but with controls, a poster frame and prefers-reduced-motion handling. The component's header documents the measurement behind that choice; here it is 274 KB of MP4 against 2.0 MB for the equivalent GIF, and the GIF loses the small UI text to dithering. The clip shows the 0.55 headline end to end: a newly added project with no chats, an 'Import 7 native chats' button, and seven terminal sessions arriving with their Imported badges and their ORIGINAL dates — which is the claim in the prose, now visible. Two stills: the root Home leading with Running then Unread across every project (0.54), and an imported chat open with the composer reading 'Message Claude…' (0.54's rename). Shot against a disposable rig holding a scrubbed copy of real data, so the volume and timestamps are genuine. Every chat title on camera was replaced with a fictional equivalent first, and the rig's data-directory footer is hidden before each frame. The page URL is unchanged: Starlight routes .md and .mdx to the same slug. * docs: runbook — recording video, and building a rig from a copy of production New material from the 0.55 pass: - The video-production harness already exists in video/ (#584). Reuse it; a new film is a directory under videos/, not a fork of lib/. - Ship MP4 through the repo's DemoVideo component rather than a GIF — 274 KB vs 2.0 MB on this clip, and the GIF loses small UI text. Records the two mechanical consequences: the page must be .mdx, and MDX rejects a JSX block placed directly after a list item. - Where media actually goes: video in public/demo/, stills in src/assets/whats-new/. A video in src/assets/ does not work. - Seeding a rig from a COPY of production, with the rsync excludes and the sidecar list, and the finding that CLAUDE_HOME does work — an older launcher's comment claiming otherwise is stale. - Scan the copy for secrets BEFORE recording: this pass found 16 files with live tokens, including the working session's own transcript. Both traps written down — grep -E with escaped braces silently matches nothing, and cat-ing a rig launcher copies a token into your transcript. - Fictionalise chat titles via PATCH before shooting rather than leaving the judgement to the reviewer. - What chat-import detection actually requires, traced from source. - Serve the built site under pm for review; Astro's dev server 403s the dev subdomain. * docs: genericise the domain in the runbook's leak-check example The example pattern named this box's private dev domain — the exact mistake the paragraph above it warns about. * docs(website): drop the What's New preamble Four paragraphs and an aside of throat-clearing before any actual release note. The page is a reverse-chronological list of what changed; it now starts with the newest entry. Removes the 'Reading older entries' aside along with it, since it sat inside the deleted range. --------- Co-authored-by: HomeLab Agent <homelab-infra@valfenda.net>
Closes #615.
The self-MCP read tools describe what they return but not what they silently discard. So callers reach for
read_chatto audit a chat and trust what comes back — which is mostly blank.The gap
read_chatrenders every tool call as arole: "tool"entry with empty text — no name, no input, no output — and those blanks still spend the caller'slimit. On a real agentic transcript they are the majority of the payload. Thinking blocks, attachments and sub-agent transcripts are dropped outright. None of that was written down anywhere: not in the tool description, not in the public reference page (which listedtoolas a valid role without mentioning those entries are empty).Observed downstream on the nightly Night-Watch reviewer:
is_errortool results — precisely the class of record this path deletes.total: 0and no error, and published "1 empty child-worktree chat" about a 1.5 MB conversation it had never opened.This is also a repeat request. Ed asked for exactly this on 2026-07-21: "ideally they would also prompt you in such a way that it tells you, 'Hey, you can use these, but also here is how you go find the actual real chats.'" A day later it became a standing manual instruction: "don't use the read chat MCP tool. It's not very good." That instruction lived nowhere in the product, so every new agent had to be told by hand — and the ones that weren't, like Night-Watch, silently did the wrong thing.
Changes
READ_CHAT_DESC— states the blank-tool behaviour and that it consumeslimit; names what else is dropped; scopes the tool to "what is this chat about / what was decided" and explicitly not "how did this chat go"; gives the transcript path (<paddock-data-dir>/projects/<slug>/.chats/<sessionId>.jsonl, sub-agents under<sessionId>/subagents/agent-*.jsonl); warns that an unknownsession_idmeans NOT FOUND rather than "empty chat".LIST_CHATS_DESC— saysnamedegrades to an 8-charactersessionIdprefix, that this means untitled, and that it is not a usable id.Public reference page (
website/src/content/docs/reference/self-mcp.md) — mirrors both, since it had the identical gap.Test — pins the disclosures so a future rewrite can't quietly drop them.
Verification
self-mcp.test.ts80 passed,mcp-transport.test.ts10 passednpm run typecheck: clean (server + web)npm run build: clean, 47 pages; confirmed the callout renders as a Starlightcautionblock and no literal:::leaked into the HTMLAssertionError: expected 'Read a trimmed tail of a chat's tran…' to match /empty/i) rather than passing vacuouslyChangeset included (
@paddock/serverpatch) — it's docs-adjacent, but these strings ship into every agent's context, so it seemed worth a release note. Happy to drop it if you'd rather treat it as docs-only.Scope notes
Description-only; no behaviour change. Two things I deliberately left out:
<paddock-data-dir>placeholder. The*_DESCvalues are static constants; threading config through would mean changing the tool-builder signature, which is more than this issue. read_chat/list_chats descriptions don't disclose what they drop or point at the raw JSONL — agents keep using read_chat for analysis it can't support #615 also floats returning apathper chat fromlist_chats— that's a real behaviour change and belongs in its own PR.project: ""silently means "all projects" #560 with a fix in flight; documenting it here would go stale on merge.Companions: #613 (the underlying fidelity defect —
toolCallis discarded inmanagement-ops.ts:218-222) and #614 (naming). This PR just makes today's behaviour honest in the meantime; if #613 lands, the first paragraph ofREAD_CHAT_DESCshould be revisited.