The explorer is told who actually reads its report - #183
Merged
Conversation
All three explorer tools shared one preamble that stated, six times, that a synthesis agent would write the final answer from the report. That is true for `consult`'s `explore′` sweep and for `deliberate`'s dossier pass. It is false for standalone `explore`, whose report goes straight back to the calling agent — `server/mod.rs` even carried a comment saying so. The decision: name the reader rather than drop the framing. Who reads the report is what makes it a hand-off instead of an answer, and an explorer that believes a rewrite is coming can reasonably leave a thread for the rewriter to pull. On `explore` nobody pulls it, so the preamble now says the report is the finished deliverable. `ReportReader` rides inside `Phase::Explorer` rather than beside it, so the reader cannot be forgotten: there is no way to name the explorer phase without deciding who reads it, and the compiler asked all four production call sites. Only the opening and one noun phrase vary — a test pins the rest of the body byte-identical across readers, so a rewrite of the reading guidance cannot land on one tool and miss the other. `kaibo://prompts` now lists the explorer phase twice, because it renders two different texts and a listing that showed one would misreport the other tool. Reading the rendered output caught a second bug the diff hid: the substituted noun phrase opens a sentence in one of the four sites, so it needed a capitalized form. `no_sentence_in_an_explorer_preamble_opens_lowercase` holds that now. Both new tests were run against the pre-fix text and fail there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kaibo's own review (cast `crusoe`, GLM-5.2 synth) read the two rendered preambles and found the seam the first pass left: "anything you leave out is missing from its answer" still implied the calling agent composes an answer from the report, one sentence after the opening said the report IS the answer. Mild, but it reintroduces exactly the framing this branch removes, so the consequence is now reader-aware too — the caller's version reads "is missing from what it can act on". That made a third phrase vary, which the shared-body test would have policed by hand. `ReaderWords` now declares every reader-varying phrase in one place, and the test normalizes through that list instead of through literals: a fourth varying phrase someone forgets to declare shows up as a body mismatch rather than slipping past. The same review found three docs describing `[prompts].explorer` as covering only "the nested `explore′` sweep inside `consult`". That was already wrong before this branch — the key has always driven all three explorer tools — and the reader split makes the omission actively misleading, so all three are corrected. `docs/config.md` also now says what an override costs: it is a full replace, so it erases the reader distinction and has to read correctly for a report handed to a synth and for one that goes straight back to the caller. One residual the review named and we are accepting: no test pins which reader each of the four production call sites passes. The type forces a choice and the comments document it, but the wiring is guarded by review. Closing it needs a seam that can observe a live call's preamble, which is a bigger change than this fix. Reviewed-by: kaibo cast `crusoe` (zai/GLM-5.2 synth, deepseek-ai/Deepseek-V4-Flash explorer) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Amy, on this PR's config prose: "a bit difficult to read, comes through very Claude-compact", and asked for an STE-like pass. The block had been a single paragraph of stacked clauses — four parentheticals, ALL-CAPS emphasis mid-sentence, and the phase list crammed onto the end of a run-on. `docs/config.example.toml` is embedded in the binary and read start to finish by whoever is configuring kaibo, so that density is charged to every reader we have. Rewritten to the rules now written down in AGENTS.md: one idea per sentence, no em-dash clause chains, the phase list as a list. It is longer in lines and smaller in distinct words, which is the trade the guide licenses — a familiar word may need a longer sentence. `sweep` is now `survey` in this text, Amy's call on the vocabulary split: `survey` is the published name for one explorer investigation pass, and it is already what `explore`'s tool description and CLI help say, so it is the one with standing. `sweep` stays the internal name in code. The rest of the published occurrences move in the style-guide branch, where the Terms table that licenses the split lives. The config.md paragraph this PR adds got the same pass, and now links to the guide instead of re-explaining the two-readers rule in the template. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tobert
force-pushed
the
explore-names-its-reader
branch
from
September 10, 2026 14:37
078f941 to
d637aa4
Compare
# Conflicts: # CHANGELOG.md
tobert
added a commit
that referenced
this pull request
Sep 10, 2026
Every built-in preamble in `src/consult/prompts.rs` now reads in one plain register: identity in one sentence, one concern per paragraph, plain imperative sentences, no capitalized section labels, and the deliverable obligation closing each prompt. The explorer used to assume source code (imports, impls, call sites, symbols). It now reads a project tree and the files a question touches, so a documentation-only repository is a normal target, and the consult driver, deliberation prompt, house-rules splice, and history framing use the same word for the same thing. This is a restyle, not a rewrite. Every phrase the tests pin survives except two that moved with their sentences, and the whole-file rule keeps all four of its registers, because the test that holds them records the measurement behind the repetition. One instruction is new in every prompt that produces a deliverable: ```text Separate what you read from what you infer and from what remains unknown. ``` The house-rules splice now says each section is headed by the path of the file it came from; the headers were already there. The consult driver's context paragraph now precedes the answer paragraph, so the prompt ends on the obligation to write the answer, where a small model attends most. For the calling agent, the gap sentence is split so "it" sits next to its antecedent: ```text Your report is the only view of this project the agent that asked receives. Anything you leave out is missing from what that agent can act on. ``` Left for a later pass: the explorer's reading guidance still repeats the kaish sandbox addendum. Stacks on #183, which must merge first. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
tobert
added a commit
that referenced
this pull request
Sep 10, 2026
Two things, and the first explains the second.
## The style pointer has been dead since 2026-08-18
AGENTS.md said: *"kaibo adopts kaish's `docs/style.md` — that guide
names kaibo as an adopter… Read it before you write help text or
operator docs."*
Both halves are false. kaish deleted that file in `e22b0be3` ("rearrange
files and remove docs/style.md") and folded its content into its own
AGENTS.md § "Writing style", which no longer mentions kaibo. So for
three weeks every reader told to go read it — a fresh session, a
subagent with no kaish checkout, a person — has found nothing. Amy asked
whether we'd ever absorbed it, after noticing #183's config prose read
"very Claude-compact". This is very plausibly why.
Absorbed into AGENTS.md directly rather than a new `docs/style.md`
(Amy's call): one file, always loaded, nothing to fetch. It costs
resident context and the trade is deliberate.
**Only what kaibo didn't already have.** "Fast and informative failures"
is covered by our error-strings paragraph, "Write for model context" by
the three-audiences block, and kaish's "Published builtin text" is
clap/ParamSchema-specific — we have our own published/internal rule.
New:
- **Vocabulary choices** — small vocabulary, plain words over figures of
speech, American spelling. Framed on the reason that actually binds
here: our synths are mostly not English-first.
- **One term, one meaning** — including the rule for a term that differs
between published and internal text.
- **Provide specific values** — the exit code, the size, the default,
the condition.
- **The example is the rule** — show the correct example first; make it
carry the rule alone.
- **A Terms table**, seeded with twelve kaibo terms that carry a
guarantee: `backend`, `cast`, `slot`, `arm`, `lane`, `phase`, `survey`,
`sweep`, `dossier`, `family`, `allowed set`, `published`. It grows when
a collision appears in real prose, not in advance — shaped to receive
later analysis rather than to be complete now.
Two deduplications, because one term, one meaning applies to the guide
itself: the `family` ruling restated what the table now defines, and the
three-audiences block argued the non-English-first case in full — it now
points at Vocabulary choices, where that argument lives once.
## `sweep` and `survey` were two words for one thing
`explore`'s tool description and CLI help say **survey**. The operator
docs said **sweep**, 26 times, never defined. A calling agent reads the
first and an operator reads the second, so the split was invisible from
either seat.
`survey` wins in published text because it is already resident — it is
in the front-door `explore` description every calling agent pays for
each session. `sweep` stays the internal name in code (~450 uses, its
own module). Converted 26 sites across `README.md`,
`config.example.toml`, `config.md`, `casts.md`, `rate-limits.md`,
`sandbox-probes.md`.
**The verb sense is deliberately untouched**, which is why this was done
by hand rather than with `sed`. "Omit `backend` to sweep every
configured backend" is ordinary English for iterating over all of
something, not kaibo's noun — three sites keep it.
**Not converted:** ~25 occurrences in tool descriptions and clap doc
comments in `server.rs`/`cli.rs`. They sit under the 2048-character
resident budget and are the text the coming prompt work will most likely
rewrite, so renaming them now would collide for no benefit. The Terms
table states that the retirement is in progress rather than implying
it's finished.
Suite: **1341 passed, 0 failed**.
Overlaps #183 in `docs/config.example.toml` and `docs/config.md` — both
sides now say `survey`, so the conflict is trivial whichever merges
first.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
All three explorer-phase tools shared one system preamble that stated, six times, that a synthesis agent would write the final answer from the report. That is true for
consult'sexplore′sweep and fordeliberate's dossier pass. It is false for standaloneexplore, whose report goes straight back to the calling agent —src/server/mod.rseven carried a comment saying so, right beside the call that sent the wrong framing.This is the first of the prompt changes coming out of the survey in
~/exomemory/briefs/agent-prompt-survey/, and the one item there that needed no research to justify: a shipped tool was telling a model something untrue about its own situation.The decision: name the reader, don't drop the framing
Who reads the report is what makes it a hand-off rather than an answer. An explorer that believes a rewrite is coming can reasonably leave a thread for the rewriter to pull — that is the correct behavior on a sweep. On standalone
explorenobody pulls it, so the preamble now says the report is the finished deliverable.ReportReader::{SynthesisAgent, CallingAgent}rides insidePhase::Explorer(ReportReader)rather than beside it. There is no way to name the explorer phase without deciding who reads it, so the reader cannot be forgotten at a call site — the compiler asked all four production sites, and each answers in a comment.Only the opening and three phrases vary.
ReaderWordsdeclares them in one place andboth_explorer_readers_share_one_bodynormalizes through that exact list, so a rewrite of the reading guidance cannot land on one tool and miss the other, and a fourth varying phrase someone forgets to declare shows up as a body mismatch rather than slipping past.kaibo://promptsnow lists the explorer phase twice, because it renders two different texts and a listing that showed one would misreport the other tool — the same class of bug this PR fixes.Two bugs found by reading the output rather than the diff
Rendering both preambles and reading them whole caught what the diff hid.
A lowercase sentence. The substituted noun phrase opens a sentence at one of the four sites, producing "Keep the report focused and evidence-first. the synthesis agent trusts your citations". Fixed with a capitalized form, and
no_sentence_in_an_explorer_preamble_opens_lowercaseholds it for both readers.A contradiction one sentence deep. "anything you leave out is missing from its answer" still implied the calling agent composes an answer from the report, immediately after the opening said the report is the answer. The consequence is now reader-aware: the caller's version reads "is missing from what it can act on".
Tests
Four, and both of the new text guards were run against the pre-fix behavior and fail there:
the_reader_reaches_the_preamble_rig_forwardsis the wiring pin: it runsexplore_withwith each reader against a scripted client and asserts on the preamble rig actually forwarded, so a hardcoded phase inside the function would fail rather than compile.Review
kaibo reviewed itself — cast
crusoe, GLM-5.2 synth over a Deepseek-V4-Flash explorer, no diff supplied. It confirmed the wiring complete across all five sites (it found the consult sweep's hardcodedSynthesisAgent, which the question hadn't named), confirmed no bypass path builds an explorer preamble outsidePhase::Explorer(reader), and found the "its answer" seam above plus three stale docs describing[prompts].exploreras covering only the nested sweep. That staleness predates this branch — the key has always driven all three explorer tools — but the reader split makes it actively misleading, so all three are corrected, anddocs/config.mdnow states what an override costs: it is a full replace, so it erases the reader distinction and must read correctly for both.One residual, accepted
No test pins which reader each of the four production call sites passes. The type forces a choice and the comments document it, but that wiring is guarded by review. Closing it needs a seam that can observe a live call's preamble — a bigger change than this fix, and a natural thing to fold into the composition seam if we build one.
Next in the stack:
consultanddeliberate, once this shape is settled.🤖 Generated with Claude Code