[FEATURE] Mods API: timestamps (and usage) on $.session.messages() rows

Status Open
Reported on v2.1.295
Maintainer reply None cached
Activity 0 comments · opened Oct 14, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

In the mods (function hooks) API, $.session.messages() returns SessionMessage rows of { role, text, toolUses, toolResults? } with no time on them. A mod that needs to know when the main conversation last called the API has to find and parse the transcript JSONL itself. One example is showing when the prompt cache expires.

That workaround is fragile:

  • session.start carries no transcript_path, so the mod rebuilds it from $.session.id() and a guessed ~/.claude/projects/<slug>/ folder. Long directory names are cut and hashed there, so in the end it falls back to scanning every project folder.
  • $.fs.read rejects files over 4 MiB, so long transcripts can't be read at all.
  • The desktop app lets an idle conversation's process go. When you come back, the mod's $.state has been reset with no resume event to rebuild it from: the session cost comes back at once ($.session.usage()), but nothing says when the last request went out.

Proposed Solution

Add timestamp (epoch ms, the transcript entry's time) to each SessionMessage returned by $.session.messages(). On assistant rows, also add the response's model and usage.

With that, "when was the last main-thread request sent, on which model, with how many prompt tokens" is a single $.session.messages() call: take the last assistant row with usage and the user row just before it.

Alternative Solutions

  • A narrower $.session.lastRequest() → { sentAt, respondedAt, model, usage } for the main thread.
  • transcript_path on SessionStartInput, so mods at least don't have to guess the path (the 4 MiB limit would still apply).

Priority

Low - Nice to have

Feature Category

Developer tools/SDK

Use Case Example

composer-meter is a mod that shows the session cost and when the prompt cache expires in the composer footer. On the terminal it also shows a usage band. The cache timer runs from the last main-thread request's start. After a resume, or after the desktop app restarts an idle session, the mod has to rebuild that from the transcript file: see hooks/transcript.ts and seedMark / transcriptOf in hooks/register.tsx. With timestamps on $.session.messages(), all of that becomes a few lines.

Additional Context

A related gap, for the same mod: turn.step's result usage (ModelUsage) has no cache_creation.ephemeral_1h_input_tokens / ephemeral_5m_input_tokens split, although the transcript records it. So a mod can't tell which TTL a request actually wrote, and has to guess from whether rate-limit windows are reported or from ANTHROPIC_API_KEY. Two mods side by side showed a 5m and a 1h countdown for the same Haiku request; the transcript says it was written with a 1h TTL. Exposing that split would let mods show the real expiry.

Seen on Claude Code 2.1.295 (types) / 2.1.296 (binary), Linux, terminal and desktop app.

View original on GitHub ↗