#4252·claude-mem

Clarify terminal preview count versus model context at SessionStart

Author: yetanotherfloCreated Sep 27, 2026Updated Sep 27, 2026

User-facing problem

The SessionStart terminal message can report fewer observations than the model-facing context actually contains. It calls its count the number of observations being loaded, without saying that it is only a shortened terminal display. This led me to believe that my configured observation limit was ignored and that Claude received less memory than it actually did. The two counts appeared during the same session start, so a user has no reason to expect them to describe different outputs.

This is a presentation issue, separate from the per-harness source filter discussed in #4245 and PR #4251.

Reproduction on my local setup

  • Windows 11, build 22631.
  • Claude Code 2.1.283.
  • Claude Code's user-installed claude-mem plugin: 13.24.1 (verified in ~/.claude/plugins/installed_plugins.json). A Codex claude-mem plugin at 13.25.3 is also installed on this machine, but the example below is from a Claude Code SessionStart. I did not independently verify which plugin bundle owned the already-running shared worker at that exact moment.
  • claude-mem uses the local SQLite data directory ~/.claude-mem and worker port 37777.
  • ~/.claude-mem/settings.json contains "CLAUDE_MEM_CONTEXT_OBSERVATIONS": "100", "CLAUDE_MEM_CONTEXT_FULL_COUNT": "10", and "CLAUDE_MEM_CONTEXT_SESSION_COUNT": "20". The terminal-output setting is unset, so its default applies.
  • Use a project with at least 100 source-matching observations and enough timeline text that the verbose colored render exceeds the hook output budget.

Steps:

  1. Start a new Claude Code session in that project with the claude-mem SessionStart hook enabled.

  2. Inspect the model-facing hookSpecificOutput.additionalContext: in my session it contained 100 observation rows and reported Stats: 100 obs (31,990t read).

  3. Inspect the user-facing SessionStart:startup says terminal block from the same hook. It contained 50 observation rows and reported Loading: 50 observations (12,015 tokens to read).

  4. The split can also be reproduced against the same local worker and project with these two GET requests. The plain response reports the model count; the colored response reports the terminal count:

    /api/context/inject?projects=<project>&platformSource=claude
    /api/context/inject?projects=<project>&platformSource=claude&colors=true

    A subsequent direct check on my worker again returned 100 for the plain request and 50 for colors=true. Counts can vary as observations change, but the two formats can consistently disagree.

Post-upgrade check (2026-09-27)

After the original reproduction, I updated the installed Claude Code plugin, Codex plugin, and shared worker to 13.28.0. The original 100-versus-50 numbers above describe the earlier setup; they should remain as the historical example. With the updated worker, the same direct comparison for project claude-mem and platformSource=claude still differs: the plain endpoint reports 50 observations (Stats: 50 obs, 6,053 response characters), while the colored endpoint reports 25 observations (Loading: 25 observations, 6,362 response characters). Both responses returned HTTP 200. This confirms the misleading count remains reproducible after aligning the installed versions; the exact counts depend on current observation content and budget fitting.

Local all-PR installation check (2026-09-27)

I installed a local composite built on 13.28.0 with my six open PRs (#3803, #4077, #4110, #4216, #4222, and #4251; composite commit c488e1c0) into the Claude Code and Codex plugins, the shared worker, and the OpenCode capture plugin. The worker reports 13.28.0 and serves the rebuilt bundle. CLAUDE_MEM_SESSION_START_INCLUDE_ALL_SOURCES=true is enabled locally; this source-filter setting is separate from the terminal-preview issue because the requests below explicitly use platformSource=claude.

The same direct GET comparison for project claude-mem still returns HTTP 200 with 50 observations in the plain model-facing response (6,053 characters) and 25 observations in the colored terminal response (6,362 characters). This confirms the mismatch remains after the local PR stack is installed.

Why it happens

src/cli/handlers/context.ts makes separate plain and colored requests, then puts the plain result in hookSpecificOutput.additionalContext and the colored result in systemMessage. src/services/context/ContextBuilder.ts fits each render independently through src/services/context/ContextBudget.ts to stay within the 10,000-character hook output limit. The colored format includes extra headings, file grouping, token columns, and ANSI color codes, so it can exceed the budget while the compact model format fits. In this example, the fitter reduced the terminal observation set from 100 to 50.

The budget mechanism from #3802 is useful. The problem is that the terminal's "Loading: 50 observations" wording reads like the actual model injection count, while the model received 100.

Desired behavior

The model-facing context remains subject to its existing 10,000-character budget. Build the terminal preview from the same selected observations in the same order that the model receives. If the terminal display needs to be shorter, simply truncate that preview and append a clear, visible disclaimer, for example: "Terminal preview truncated; Claude received additional observations in its model context."

The terminal should never label only the displayed subset as the total number of observations being loaded. It may show both counts when useful, for example: "50 observations sent to the model; terminal preview truncated after 25." If the preview fits, show the full selected set without a truncation disclaimer. Please add a regression case where verbose terminal formatting would previously have selected fewer observations than the plain model format, and assert that the terminal instead follows the model's selection and discloses any display truncation.