Fix Sessions Endpoint in Activity Feed

Claude Code·Opus 4.8[1m]·Soph·2mo ago·6hr 33min·2 Checkpoints·9 file changes·+609/-76·257.1K tokens

which endpoint are we calling now for the sessions

2mo ago·1m

For the activity/recap surface (the /me/* work on this branch), the session data comes from GET /api/v1/me/activity — see activity_cmd.go:117 (fetchActivity). Alongside it are GET /api/v1/me/commits (activity_cmd.go:137) and GET /api/v1/me/recap (recap/me_recap.go:143), and recap's response carries the per-scope sessions count.

What changed "now" is which backend serves those paths, not the paths themselves. As of 077b7479e, these commands go through runAuthenticatedActivityAPI (entireapi_client.go:35), which:

  1. Tries the caller's home entire-api cell via auth.NewEntireAPICellClient (same client experts uses).
  2. Falls back to the data API (runAuthenticatedDataAPI) on any failure — no cell in the region yet (ErrNoCellForJurisdiction), not logged in (ErrNotLoggedIn), or a discovery/exchange error.

Both backends expose the identical /me/* paths, so the fetch code (fn) is agnostic to which client it gets. You can hit it manually with entire api --to cell /api/v1/me/activity.

Two things that are not this endpoint, in case you meant one of them:

  • entire sessions list (agent sessions) reads local session state from .git/entire-sessions/, no API call.
  • Login/auth sessions (auth status, logout) still hit entire-core at /api/auth/tokens (auth.go:27), unchanged by this branch.

Which "sessions" did you mean?

yeah sorry I meant the activity page for example, because it lists different sessions then what entire.io lists who uses GET /api/v1/me/sessions?timeframe=<tf>&limit=<n>

2mo ago·41.1s

Right — that's the mismatch. The CLI's entire activity never calls /me/sessions. It builds its view from two other endpoints:

  • GET /api/v1/me/activity → aggregate only: stats, hourly_contributions, repos[] (activity_cmd.go:112)
  • GET /api/v1/me/commits → the commit list, each with nested checkpoints[] (activity_cmd.go:136)

So the CLI has no session-list concept at all. Whatever "sessions" it appears to show are actually commits grouped by day (groupCommitsByDay, rendered at activity_cmd.go:83-86), and its only session-derived number is the Iteration stat — "avg session_count per checkpoint" (activity_types.go:66), which comes from userCommitCheckpoint.SessionCount on the commits payload.

entire.io's activity page, by contrast, lists real session records from GET /api/v1/me/sessions?timeframe=<tf>&limit=<n>. Different source, different grain (per-session vs per-commit), so the two lists won't line up — a commit can bundle several sessions, and a session with no resulting commit won't appear in the CLI at all.

Grep confirms it: no /me/sessions reference anywhere in the CLI.

Do you want me to point the CLI at /api/v1/me/sessions so it lists the same sessions as the web — either replacing the commits-derived view or adding a session list alongside it? If so, I'd need the response shape /me/sessions returns (or I can pull it from the entire-api handler / the entire.io frontend in the devenv monorepo to model the Go types).

yes, cli should do the same as the entire.io page, but we should stack it onto https://github.com/entireio/cli/pull/1641

2mo ago·12m

I'll skip the task tracker for now and wait for the frontend exploration to complete — I'll pick the work back up when it reports.

2mo ago·1h 37m

Done. The feature is implemented, tested, and committed on a branch stacked on #1641.

What changed

entire activity's recent list now shows sessions (from GET /api/v1/me/sessions) by default, matching the entire.io Overview page. Commits move behind entire activity --commits.

  • Sessions feed — fetched at limit=50 (mirroring the web's USER_OVERVIEW_RECENT_SESSIONS_LIMIT), grouped by local day of lastActivityAt (newest first), one row per session with the same fields the web row shows: display name (capped at 120), repo, public tag when isPublic, agent badge, friendly model label, and checkpoint count. Stat cards / heatmap / repo chart (from /me/activity) are untouched.
  • formatModel ported from entire.io/frontend/src/lib/model.ts to Go, with the same test cases (claude-opus-4-6→"Opus 4.6", gpt-4o→"GPT-4o", gemini-2.0-flash→"Gemini 2.0 Flash").
  • Routing — reuses runAuthenticatedActivityAPI, so /me/sessions goes to the caller's home entire-api cell with the data-API fallback (the #1641 plumbing).
  • Dedup — extracted fetchActivityWith (activity + chosen list, concurrent) and generic groupItemsByDay so the commit and session paths share logic.

Files: model_label.go (+test), activity_sessions_test.go new; activity_{cmd,render,tui,types}.go + activity_cmd_test.go modified. agent-help picks up the new --commits flag automatically (renders live from the cobra tree).

Verification

  • mise run fmt clean, mise run lint 0 issues, mise run test:ci green (unit + integration + Vogon canary, 0 failures).
  • One caveat handled: golangci-lint --fix locally tried to strip a pre-existing //nolint:exhaustive in explain.go (unrelated; identical to origin/main). I discarded that — removing it could trigger a new exhaustive error under CI's linter version, and CI's only-new-issues won't flag the untouched line.

Stack

  • Branch soph/cli-activity-sessions-list → based on soph/cell-routing-foundation (#1641, tip 9ef8a5cff). Commit 607d2ec26, Entire trailer attached.
  • Note: #1641 itself is still behind main (branched at 86a21a829); it'll need a rebase before/at merge, and this stacks on top.

I held off on pushing / opening the PR since that's the outward-facing step. Want me to push and open the PR against soph/cell-routing-foundation? If so I'll write it up referencing #1641 as the base.

ok, can you rebase onto main? 1641 has merged

2mo ago·10m

Rebase is done — 887f76405 sits cleanly on top of current origin/main (which includes the merged #1641), build and lint are clean, and cli package tests pass. Full test:ci is running in the background; I'll report the result when it completes.

2mo ago·17.2s

Rebase complete and fully verified.

State

  • Branch soph/cli-activity-sessions-list → commit 887f76405, sitting cleanly on top of origin/main (which now includes the merged #1641). No longer stacked — its base is plain main.
  • test:ci green on the rebased branch (exit 0, 0 failures — unit + integration + Vogon canary), plus mise run lint 0 issues and a clean working tree.

The explain.go --fix artifact from before is gone — the new main already reconciled that nolint, so lint no longer touches it.

The branch is unpushed. Want me to push it and open the PR against main? I'll write the PR body describing the sessions-vs-commits switch, the formatModel port, and the --commits flag (and drop the "stacked on #1641" note since it's now merged).

Check the test:ci background job (be06r7pw1) result for the rebased sessions branch and report pass/fail.

2mo ago·11.0s

The test:ci job (be06r7pw1) already completed: PASS — exit code 0, 0 failures across unit + integration + Vogon canary. Nothing else pending from that run.

Current state of the rebased branch soph/cli-activity-sessions-list (887f76405, on top of origin/main): test:ci green, mise run lint 0 issues, clean working tree.

It's still unpushed — say the word and I'll push it and open the PR against main.

ok, let's push and open a PR

2mo ago·44.7s

PR opened: https://github.com/entireio/cli/pull/1650

  • Branch soph/cli-activity-sessions-list (887f76405) pushed, PR base main.
  • Body covers the sessions-vs-commits switch, the --commits flag, the formatModel port, the /me/sessions cell routing, and the isPublic caveat — plus the test summary (fmt/lint/test:ci all green).

You may want to keep an eye on the automated reviewers (Bugbot/Copilot/Cursor) that commented on your recent PRs; happy to address their findings when they land.

can you check the comments on the PR?

2mo ago·59.3s

Checked. Here's the full picture on PR #1650:

CI — all green

Cursor Bugbot (pass, no findings), lint, test, test-canary (git-branch + git-refs), test-integration (a/b/c), test-core, binary-size, licenses — all pass.

Reviews

Only Copilot has reviewed so far, with 1 inline nit (activity_render.go:583):

The 120-rune title cap slices to sessionTitleMaxRunes and then appends an ellipsis, yielding a 121-rune string. If this is meant to be a hard 120-char cap, the slice should leave room for the ellipsis (or the comment/constant should be updated).

My assessment: benign, and the code is intentionally correct. The web does displayName.slice(0, 120) + "..." — i.e. it caps the content at 120 and appends an ellipsis on top (so the web string is up to 123 chars). Mine keeps 120 content runes + a 1-rune "…" = 121. So my output mirrors the web's intent faithfully; slicing to 119 would actually make it less faithful. Also, in practice the width-based truncation almost always kicks in first on a real terminal, so this cap is a belt-and-suspenders match to the web.

The only fair point is wording: "120-char cap" could read as a hard total. I'd tweak the comment to say the cap is on the display-name content (matching the web's slice(0,120)), and leave the slicing as-is.

Want me to push that one-line comment clarification, or leave it and mark the Copilot comment as addressed with a reply explaining the parity?

yes, please do

2mo ago·2m

Done — Copilot's comment is addressed on PR #1650.

  • Commit a7dcecd2d pushed: reworded the sessionTitleMaxRunes comment so it's unambiguous that 120 caps the display-name content (matching the web's slice(0, 120) + "…"), with the ellipsis appended on top. No behavior change — the slicing stays as-is because changing it would diverge from the web. Lint clean.
  • Replied to the inline comment explaining the parity (visible here).

Recap of the PR's review state: all CI green (lint, tests, both canaries, all integration shards, Cursor Bugbot pass), and the sole review nit (Copilot) is now resolved. The PR is clean and ready for a human review whenever you want to merge.