Skip to content

prompt.context / prompt.section: pay the ops roster on first use instead of injecting it at session start #2295

Description

@fdaviddpt

Follows #2293. Two of the function-hook events are context sites, and they are the direct answer to "bytes charged to every session to serve some sessions are a cost, not a feature".

From @anthropic-ai/claude-code-darwin-arm64@2.1.260 (verified 2026-09-04):

kAe = { site: am["prompt.context"],
        core: { name:"core", isCore:true, budgetMs:0, run: async (e) => ({ blocks: e.blocks }) } }

prompt.context receives { blocks } and returns { blocks } — the whole computed context, last stop before the model. Core is identity, so an empty chain changes nothing. It fails open, and the log line says exactly that: prompt.context: the dispatch failed, the context stands as core computed it: <err>.

prompt.section is the same site one level down: { name, text } in, { text } out, text: null drops the section, and per the binary's own check message "the engine caches the section by it" (the name). There is a refreshContext() to invalidate, and each site carries a budgetMs.

What this costs today. From a real session preamble, 2026-09-04:

SessionStart hook additional context: 14119101 bytes, at or past the 10000000 byte watch threshold (#248)

and beside it a 13.2KB handoff that could not be printed and was spilled to a file for the agent to go read. All of it injected at session start, before anything knows whether the session touches supertool at all.

Three things this buys, in the order worth trying:

  1. Pay the roster on first use. Register the ops table as a named section that returns null, and on the first supertool tool.call, refreshContext() and return the real text. A session that never calls supertool never pays for its signature table. Today it always does.
  2. Stop re-sending what has gone stale. The handoff and board blocks are computed once at start and are wrong for the rest of the session. A section keyed by name and invalidated on turn.complete is recomputed rather than stale — and a stale block that reads as current is this repo's own defect class (CLAUDE.md, "an absence produced by the tool, read as an absence in the world").
  3. Get the injection off the hook output cap. Session-start injection is a command hook and its stdout is capped at 10,000 characters, which is why the handoff spills to a file. A context site hands blocks directly: no stdout, no cap, no spill.

The fail-open is what makes (1) safe to try first: if the module throws, the context is what core computed, which is today's behaviour exactly.

Open questions:

  • What the trigger for (1) actually is. "First supertool call" is the obvious one, but a session can need the roster before it calls anything — that is the whole point of injecting it. Getting this wrong makes the tool invisible rather than cheap, which is worse than the bytes.
  • Whether budgetMs is enough to compute a block that shells out. The roster is cheap; the board is not.
  • How this interacts with .claude/jit-context/. The jit rules already solve "cost nothing until the match fires" for path- and tool-matched rules. This is the same idea for the always-on block, and the two should not end up as two mechanisms answering one question.

Blocked on the same flag as #2293: CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1, flag tengu_plugin_hooks_modules, GrowthBook-gated.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

cohort-29Open at the v0.60.0 tag, 2026-09-11. Frozen: nothing joins a cohort.cohort-30Open at the v0.61.0 tag, 2026-09-12. Frozen: nothing joins a cohort.cohort-31Open at the v0.63.0 tag, 2026-09-19. Frozen: nothing joins a cohort.cohort-32Open at the v0.64.0 tag, 2026-09-23. Frozen: nothing joins a cohort.enhancementNew feature or requestlane-containmentpayload gate and trust model — reaches into other lanes, wants their reviewpriority-mediumRecurring cost; compounds if unfixed

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions