forge: detect channel status from Claude's transcripts, not the status line #15

Merged
pedromcaraujo merged 1 commit from status-dots-without-statusline into main 2026-07-28 07:11:51 +01:00

Summary

The per-channel status dots keyed off a $0.71-style spent-cost readout in
Claude's status line. That readout isn't present in a customised status line,
so every channel with a live conversation started reporting "fresh".

/status now reads the session state from Claude's own transcripts: slugify
the pane's #{pane_current_path} to ~/.claude/projects/<slug>/ and check
whether any session .jsonl was written at or after #{session_created}.
Claude appends on every turn, so this holds whatever the status line renders.

The screen scrape stays as a fallback for when the projects directory can't
answer (missing/unreadable, or a pane whose cwd moved), but now keys off the
transcript's own rendering — the / bullets and the running-turn hint —
rather than the status line.

FORGE_CLAUDE_PROJECTS overrides the projects root for testing. The
forge-tmux service runs as the session owner with no ProtectHome, so it
can read the directory.

Test plan

  • Ran /status against six live channels — all six classify correctly,
    including nixos (fresh: placeholder prompt, 0% context) vs homelab
    (active: 103.9k context). The old cost heuristic called every one fresh.
  • Those panes had no left in the visible scrollback, so the transcript
    check is doing work the screen scrape couldn't.
  • Slug rule verified against the real directory names, including
    /home/pma/workspace/wine_radar-home-pma-workspace-wine-radar.
## Summary The per-channel status dots keyed off a `$0.71`-style spent-cost readout in Claude's status line. That readout isn't present in a customised status line, so every channel with a live conversation started reporting "fresh". `/status` now reads the session state from Claude's own transcripts: slugify the pane's `#{pane_current_path}` to `~/.claude/projects/<slug>/` and check whether any session `.jsonl` was written at or after `#{session_created}`. Claude appends on every turn, so this holds whatever the status line renders. The screen scrape stays as a fallback for when the projects directory can't answer (missing/unreadable, or a pane whose cwd moved), but now keys off the transcript's own rendering — the `⏺`/`⎿` bullets and the running-turn hint — rather than the status line. `FORGE_CLAUDE_PROJECTS` overrides the projects root for testing. The `forge-tmux` service runs as the session owner with no `ProtectHome`, so it can read the directory. ## Test plan - [x] Ran `/status` against six live channels — all six classify correctly, including `nixos` (fresh: placeholder prompt, 0% context) vs `homelab` (active: 103.9k context). The old cost heuristic called every one fresh. - [x] Those panes had no `⏺` left in the visible scrollback, so the transcript check is doing work the screen scrape couldn't. - [x] Slug rule verified against the real directory names, including `/home/pma/workspace/wine_radar` → `-home-pma-workspace-wine-radar`.
forge: detect channel status from Claude's transcripts, not the status line
All checks were successful
CI / check (pull_request) Successful in 28s
9ca2195908
The per-channel status dots keyed off a `$0.71`-style spent-cost readout in
Claude's status line. That readout is not part of a custom status line, so
every channel with a live conversation started reporting "fresh".

Read the session state from Claude's own transcripts instead: slugify the
pane's cwd to `~/.claude/projects/<slug>/` and check whether any session
`.jsonl` was written at or after the tmux session started. Claude appends on
every turn, so this holds whatever the status line renders.

The screen scrape stays as a fallback for when the projects directory can't
answer, but now keys off the transcript's own rendering (the `⏺`/`⎿` bullets,
the running-turn hint) rather than the status line.

Checked against six live channels: all six classify correctly, where the cost
heuristic called every one of them fresh.
pedromcaraujo deleted branch status-dots-without-statusline 2026-07-28 07:11:52 +01:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
pedromcaraujo/forge!15
No description provided.