Skip to content

[bug]: claude-mem's gateway (GLM) usage silently stops being counted — claude-mem 13.12.4 spawns the CLI with --no-session-persistence #128

Description

@pitimon

What happened?

A previously-tracked source went to zero and nothing reported it. claude-mem is still making
Claude-CLI calls against a third-party Anthropic-compatible gateway (glm-5-turbo) all day, but as of
2026-07-28 ~18:00 (+07) TokenTracker counts zero of them. tokentracker doctor stays green.

Root cause is external to TokenTracker — claude-mem v13.12.4 started spawning its Claude Code CLI
child with --no-session-persistence, so no session .jsonl is written anywhere. TokenTracker's
only ingest surfaces are ~/.claude/projects/** and ~/.codex/sessions/**, so the data simply stops
existing. I'm filing it here anyway because (a) that source was 84% of my tracked Claude Code files,
and (b) the failure mode is silent — which is the part TokenTracker can fix.

The seam

Last observer-session transcript written 2026-07-28 18:00 (+07)
Last glm-5-turbo bucket in queue.jsonl hour_start = 2026-07-28T10:30:00.000Z (= 17:30 +07)
claude-mem v13.12.4 plugin files installed 2026-07-28 18:00 / .install-version 18:25
GLM calls still happening after that yes — see below

Transcript files per day in ~/.claude/projects/<slug of ~/.claude-mem/observer-sessions>/:

2026-07-25   128
2026-07-26    11
2026-07-27     8
2026-07-28    52     <-- stops at 18:00
2026-07-29     0
2026-07-30     0

…while claude-mem's own database shows the work never stopped
(select date(created_at), count(*) from observations where generated_by_model='glm-5-turbo', shifted to +07):

2026-07-28   714
2026-07-29   252     <-- 0 tokens recorded by TokenTracker
2026-07-30    77     <-- partial day, 0 tokens recorded

Volume now invisible

Daily glm-5-turbo totals TokenTracker did capture, from ~/.tokentracker/tracker/queue.jsonl
(billable_total_tokens, bucketed to +07):

2026-07-25    80,624,877
2026-07-26   157,549,828
2026-07-27    68,610,858
2026-07-28   102,386,382
2026-07-29             0
2026-07-30             0

Rough estimate of the gap: Jul-28 ran ≈143k billable tokens per observation (102.4M / 714). Applying
that ratio to the 329 observations since the seam ⇒ ~47M billable tokens untracked in under two days.
Estimate, not a measurement — the real number is only knowable at the gateway now.

Root cause evidence

The live CLI child of the claude-mem worker (ps -o command=, secrets omitted):

claude --output-format stream-json --verbose --input-format stream-json
       --model glm-5-turbo
       --permission-prompt-tool stdio
       --disallowedTools Bash,Read,Write,Edit,Grep,Glob,WebFetch,WebSearch,Task,NotebookEdit,AskUserQuestion,TodoWrite
       --setting-sources= --strict-mcp-config --permission-mode dontAsk
       --no-session-persistence

Claude Code's own help text for that flag: "use --no-session-persistence to disable transcript writes
entirely."
In claude-mem's bundle the flag comes from persistSession: false set in code — there is no
CLAUDE_MEM_* setting that turns it back on.

Ruled out: the Claude Code CLI itself. ~/.local/bin/claude has been pinned to 2.1.220 since
2026-07-25, and transcripts kept appearing 07-25 → 07-28. The only thing that changed at the seam is
claude-mem 13.11.0 → 13.12.4.

Verified: no drop-in replacement source exists today

I looked for somewhere else to read this usage from before filing:

  • claude-mem.dbobservations.discovery_tokens is 0 for every recent row; sdk_sessions has
    no token columns at all (id, content_session_id, memory_session_id, project, platform_source, user_prompt, started_at*, completed_at*, status, worker_port, prompt_counter, custom_title).
  • claude-mem worker HTTP API (:37701) exposes ~39 endpoints; none carry usage/token data.
    /api/stats returns only {worker:{version,uptime,activeSessions,sseClients,port}, database:{path,size,observations,sessions,summaries,firstObservationAt}}.
  • No .jsonl anywhere under $HOME (outside TokenTracker's own queue) contains a "model":"glm…"
    record after the seam.

So the token data is genuinely gone at the source. Nothing for TokenTracker to parse.

Why I think this still belongs here

  1. It fails silently, and silence looks identical to "you didn't use it". No error, no gap marker,
    no dashboard warning. tokentracker doctor reports ok 9 | warn 1 | fail 0 | critical 0 — the one
    WARN is an unrelated queue.row_invariant (2 rows in 6,343).
  2. It's a class, not a one-off. --no-session-persistence is a public Claude Code flag. Any
    SDK/CLI consumer can opt out of transcripts at any time and become invisible. "Transcripts exist"
    is an assumption TokenTracker currently treats as guaranteed.
  3. The blast radius here was large: cursors.json tracks 14,630 files — 14,048 under
    ~/.claude/projects, 582 under ~/.codex/sessions — and 12,314 of them were claude-mem
    observer sessions. Roughly 84% of the Claude Code ingest surface stopped producing new data and
    nothing noticed.

Steps to reproduce

  1. Point a Claude Code consumer at a third-party Anthropic-compatible gateway — for claude-mem, put
    ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN in ~/.claude-mem/.env and set
    CLAUDE_MEM_MODEL=glm-5-turbo, CLAUDE_MEM_PROVIDER=claude in ~/.claude-mem/settings.json.
  2. On claude-mem ≤ 13.11.0, use Claude Code normally → transcripts appear under
    ~/.claude/projects/<observer-sessions slug>/ and TokenTracker counts glm-5-turbo usage.
  3. Upgrade claude-mem to 13.12.4 and keep working.
  4. Confirm the calls are still happening:
    sqlite3 ~/.claude-mem/claude-mem.db "select generated_by_model, count(*) from observations where created_at > '<upgrade time>' group by 1"
    glm-5-turbo | N with N > 0.
  5. Confirm the child is spawned without persistence:
    pgrep -lfP $(pgrep -f 'worker-service.cjs --daemon') → argv contains --no-session-persistence.
  6. Check TokenTracker → no new glm-5-turbo buckets after the upgrade timestamp; doctor still green.

Expected behavior

TokenTracker shouldn't be able to silently lose a source. At minimum I'd expect a visible
"source went quiet" signal; ideally a way to keep accounting for gateway spend that no longer
lands in a transcript.

Proposed fixes (ranked, happy to PR any of these)

  1. Source-staleness detection — cheapest, most general, would have caught this the same evening.
    Keep a per-source (and optionally per-model) last_seen. If a source that produced ≥ N tokens/day
    for K consecutive days drops to zero for more than X hours, emit a WARN in doctor and a banner
    on the dashboard / menu-bar app. Thresholds configurable; default something forgiving like
    "was active 3 of the last 7 days, silent > 24h".
  2. Document the transcript assumption — a short note that ingest depends on session .jsonl
    files, that --no-session-persistence (and any SDK caller passing persistSession: false)
    defeats it, and how to spot it. Plus a doctor check that greps live claude processes for the
    flag would be a nice concrete touch.
  3. Optional gateway reconciliation — config for an Anthropic-compatible gateway (base URL +
    usage endpoint + token) so third-party spend can be pulled independently of transcripts. This is
    the only path that gives accurate numbers for the current claude-mem behavior, rather than just
    flagging the hole.
  4. Upstream ask (I'll file separately with claude-mem) — either expose per-session token usage on
    the worker's /api/stats, or make persistSession a CLAUDE_MEM_* setting so users who track
    spend can opt back in. If claude-mem grows a usage endpoint, TokenTracker could add it as a
    first-class source.

Environment

  • TokenTracker version: @ipv9/tokentracker-cli 0.39.44 (running from ~/.tokentracker/tracker/app, LaunchAgent dashboard)
  • Node.js: v26.0.0
  • OS: macOS 26.5.2 (Apple Silicon)
  • Claude Code CLI: 2.1.220 (unchanged since 2026-07-25)
  • claude-mem: 13.12.4 (was 13.11.0 until 2026-07-28 ~18:00 +07); worker healthy on 127.0.0.1:37701
tokentracker doctor output
Doctor report

- [OK] runtime.dashboard_url - dashboard_url unset
- [OK] runtime.http_timeout_ms - http timeout resolved
- [OK] runtime.debug - debug disabled
- [OK] runtime.node_version - Node.js v26.0.0 satisfies >=20
- [OK] browser.opener - open available
- [OK] fs.tracker_dir - tracker dir readable
- [OK] fs.config_json - config.json readable
- [OK] cli.entrypoint - cli entrypoint readable
- [WARN] queue.row_invariant - 2 row problem(s) in 6343 line(s)
- [OK] notify.configured - notify configured

Summary: ok 9 | warn 1 | fail 0 | critical 0

Note the report is green while an 84%-of-files source is producing nothing — that's the gap
proposal #1 is aimed at. (The queue.row_invariant WARN is unrelated and pre-existing.)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions