anthropics / anthropics/claude-code
[FEATURE] /insights --project <path>: scope the report to a single project directory
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 146k
- Forks
- 23.8k
- PR merge metrics
- PR metrics pending
Description
Preflight Checklist
- I have searched existing requests and this feature hasn't been requested yet
- This is a single feature request (not multiple features)
Problem Statement
/insights analyses every session on the machine and offers no way to scope the report to one project. For anyone using Claude Code across more than a handful of repositories, the report is a portrait of whichever project they use most, and the question "how is my work on this project going?" cannot be asked.
Measured on my machine (~/.claude/usage-data/session-meta/, v2.1.278, re-measured 2026-09-19):
- 4,294 session-meta records across 634 distinct project_path values
- Of those 634: 50 real project directories, 158 git worktrees beneath them, and 426 throwaway /tmp/… directories from hook-isolation test runs
- The project I want insights for today: 53 sessions — 1.23% of the corpus
- Top three projects: 45.2% of all sessions
Two properties of that corpus make the share worse than 1.23% suggests.
76.9% of the records are zero-signal. 3,301 of the 4,294 carry exactly 2 "messages", zero assistant turns, zero tool calls, zero tokens, zero duration and first_prompt: "No prompt". Their transcripts show what they are — a session that ran one local slash command and exited before any model turn:
7f020908-….jsonl 10 lines {'queue-operation': 2, 'attachment': 4, 'user': 2, 'system': 1, 'last-prompt': 1}
| <command-name>/usage</command-name>
Only 945 records (22.0%) contain any assistant turn or any tool call. A /usage invocation is counted as a session, sits in the denominator, and sits in the sampling pool beside a six-hour build session. Among substantive records my project is 8 of 945 — 0.85%.
Session count is the wrong unit anyway. Across those 53 sessions the median is 2 messages; 45 of 53 carry ≤5 messages, 90 messages between them — 7.6% of the project's volume — while a single session carries 37.3% and the top five carry 80.3%. Machine-wide the same shape: median 2 messages per session, and the top 10% of records carry 81.8% of all messages. A uniform sample over sessions is therefore a sample of stubs, and the handful of sessions where the design decisions and the friction actually live are exactly the ones it misses.
The narrative sections, friction patterns, tool-usage profile and recommendations are all generated over the whole corpus, so there is nothing project-specific to read around — the analysis was never about my project.
It is worse than the share suggests, because the report samples. My latest report header:
4,956 sessions total · 490 analyzed · 6,764 messages · 2026-07-15 to 2026-09-19
490 of 4,956 analysed. If that sample is uniform over records, the expected number of my project's sessions inside it is five, of which — at the 8-in-53 substantive rate above — the expected number carrying any content at all is under one. Any sentence about that project rests on nothing, unlabelled, mixed into 489 others, and the header states neither which projects were included nor how many. A reader cannot tell it is a 50-repository aggregate.
This is not an unusual setup. It is the normal shape of a working machine: a few large long-running projects and a long tail of small ones. The long tail is where insight is most useful — a new project, an unfamiliar stack, a repo where something is going wrong — and it is exactly what the global aggregate drowns. The 426 /tmp throwaways are a second reason: nobody wants hook-isolation test runs in their workflow analysis, and today there is no way to exclude them.
The data is already collected. Every session-meta record carries project_path as a first-class top-level field:
{
"session_id": "…",
"project_path": "/home/me/projects/auxiliary/kanjin",
"start_time": "2026-09-02T09:48:20.173Z"
}
Nothing new needs to be gathered, stored or computed. The corpus is already keyed by project. Only the filter is missing.
Proposed Solution
Add an optional project scope to /insights. Prior requesters converged independently on almost exactly this shape, so it is well-tested as a design:
/insights # unchanged — all projects, current behaviour
/insights --project . # sessions whose project_path is under the cwd
/insights --project <path> # prefix match on project_path
/insights --exclude <path> # optional, inverse — e.g. --exclude /tmp
Default behaviour must not change. A bare /insights keeps analysing everything. Strictly additive, opt-in: no migration, no deprecation, nothing changes for anyone who does not pass the flag.
Prefix match, not equality. Sessions started in a git worktree record /.claude/worktrees/ as their project path — on my machine 331 sessions across 158 worktree paths. A prefix match on the repository root folds them into their parent project, which is what a user means by "this project". Equality would silently drop them.
Minimal viable version, if the flag set is too much — a single optional positional path, as #29844 proposed:
/insights /home/me/projects/thing
Implementation is a predicate at load time, before sampling and before facet generation:
sessions.filter(s => s.project_path.startsWith(resolvedScope))
Everything downstream — sampling, facet extraction, narrative generation, charts, the HTML report — runs on the filtered set unchanged.
Two cheap additions that would make it materially better:
-
State the scope in the report header. Today it prints messages, sessions and a date range. It should also print the projects included, the in-scope session count and how many of those were substantive rather than zero-signal, so a scoped report cannot be mistaken for a global one — and a global one is honest about being an aggregate of N projects.
-
Print the in-scope session count before generating. A scoped run over 4 sessions should say so rather than silently producing thin narrative. This also addresses the long tail of "empty report" issues (#64275, #83849, #83695, #81679 and others), where low input volume yields empty AI sections with no explanation.
Alternative Solutions
Tried, or considered and rejected:
-
Deleting or moving other projects' session-meta files. What #56332's author resorted to. It destroys global history to get one scoped report, and must be redone every time.
-
Running /insights and reading around the noise. Not viable at 0.85% signal against a 490-session sample. The narrative is generated over the full corpus; there is nothing project-specific in it to read around.
-
Parsing session-meta/*.json myself. I did, to produce the figures above. It yields counts only. The value of /insights is the qualitative facet analysis and the narrative, and there is no supported way to invoke those over a subset.
-
A separate machine or OS account per project. #41199's author genuinely did this — backend on a VM, UI on a different desktop — and reported it still fails for two projects on one desktop. Not serious for 51 projects.
-
Date filtering (--since/--until) as a proxy. Would partly help someone who works on one project at a time. It has also been requested nine times and has not shipped either, so the whole filtering family is unaddressed.
No workaround preserves the feature's actual value.
Priority
High - Significant impact on productivity
Feature Category
CLI commands and flags
Use Case Example
A real scenario from this morning.
-
I maintain a small personal-health tracking project: 53 sessions, active, the one I am developing today. Its git history runs to 106 commits since 2026-04-03, but session-meta holds nothing before 2026-09-02 — machine-wide the corpus floor is 2026-07-15, so it is a rolling window rather than a history, which is a second reason the report cannot answer a question about a project.
-
I also maintain two large infrastructure repositories with 973 and 700 sessions, plus 47 other real projects, 158 worktrees and 426 throwaway test directories — 4,294 sessions in all.
-
I want to know: on this project, where is my time going, what is my tool-error profile, where is the friction, what should I change?
-
I run /insights. It samples 490 of 4,956 machine-wide; on expectation fewer than one of them is a substantive session of mine. I get a report about my two largest repositories.
-
No flag, prompt or setting changes this, so the question is unanswerable with the tool that exists to answer it.
With /insights --project . I get a report over those 53 sessions and an actual answer.
Three further situations, each raised independently in the prior issues:
-
Work / personal separation (#30208, #41199). A report for a professional context should not be part-built from personal sessions. As things stand an /insights report is not shareable at work by anyone who also uses Claude Code at home.
-
Suggestions become actively misleading, not merely diluted (#41199). The "Suggested CLAUDE.md Additions" section emits copy-pasteable rules derived from patterns aggregated across projects. That commenter's report suggested a Docker-based lint hook correct for one project and wrong for another they were "tempted to paste it into". A blended corpus does not just under-inform; it produces guidance that is harmful if acted on, which defeats the ready-to-copy framing of that section.
-
Friction metrics lose meaning when averaged across incompatible workflows (#41199). "Wrong Approach: 22" summed over projects with different languages, conventions and CLAUDE.md files is not signal. The same applies to project-area clustering, tool-use distribution and the satisfaction histogram.
Additional Context
This request has been filed 31 times before. None was decided on its merits.
I swept the issue tracker for every wording — scope, project, filter, directory, cwd, repo, per-project, workspace — across open and closed. The result is 32 issues including this one, in three families that share one root cause: /insights cannot be told which sessions to analyse.
| Family | Issues | 👍 | ❤️ | Locked |
|---|---|---|---|---|
| Project scoping | 17 | 6 | 3 | 17 / 17 |
| Date-range filtering | 9 | 24 | 8 | 7 / 9 |
| Sampling & population bias | 6 | 1 | 0 | 6 / 6 |
| Total | 32 | 31 | 11 | 30 / 32 |
How the 31 were closed: 15 by the stale bot, 12 by the duplicate bot, 5 by their own authors or by other users triaging. Zero by a maintainer. Across all 32 there is not one comment from anyone with a maintainer association — every human commenter is author_association: NONE. No triage label beyond area:*. No explanation. No decision, in either direction, in nineteen months.
Full list, verified via the GitHub API on 2026-09-19
Project scoping (17) — #23311 (4 👍, stale), #23762 (dup → #23311), #23914 (dup → #23762), #24103 (dup → #23914), #26261 (dup → #18718), #28025 (2 👍, dup → #23762), #28153 (closed by a third party), #28301 (closed by its author), #29844 (dup), #30208 (3 ❤️, dup → #23076), #31106 (closed by its author), #32054 (dup → #23311), #41199 (stale), #47908 (closed by a third party), #48451 (stale), #49025 (stale), #56332 (stale)
Date-range filtering (9) — #23076 (7 👍, stale), #26601 (2 👍, stale), #29539 (11 👍, 7 ❤️, stale), #32356 (2 👍, stale), #56841 (stale), #58577 (1 ❤️, dup → #29539), #59817 (dup), #78067 (stale, closed 2026-09-19), #82928 (2 👍, stale)
Sampling and population bias (6) — #22998 (1 👍, stale), #23361 (dup → #22998), #25038 (stale), #26020 (stale), #26300 (closed same day), #58165 (dup → #26300)
Four things follow.
1. The duplicate bot routes into graves, and sometimes into the wrong grave.
Every duplicate target was already dead or died shortly after:
#24103 → #23914 → #23762 → #23311 → stale-closed
#28025 → #23762 → #23311 → stale-closed
#30208 → #23076 → stale-closed the same day
#58577 → #29539 → stale-closed
#23361 → #22998 → stale-closed
Consolidation into a closed thread is not consolidation. And #26261 — a request about /insights aggregating across accounts — was folded into #18718, a Windows cross-account authentication security bug, which then went stale itself. That is misrouting, not deduplication.
2. The strongest signal in the family was closed while people were still arguing for it.
#29539 carries 11 👍 and 7 ❤️ — the largest in the set — with four separate supporting comments, including a user reporting "1,825 total sessions but only 76 were analyzed — covering just ~16 days". The stale bot closed it on 2026-06-02. A participant's entire next comment was "Wtf". It was locked two months later.
3. Somebody offered to write the code and nobody answered.
On #41199, 2026-04-14: "can we open a pr for this functionality directly or does this need to be triaged before work?" No reply, from anyone, ever. The issue was stale-closed seven weeks later. I make the same offer below, and it stands.
4. Locking is why this keeps recurring, and why a new issue is the only route.
30 of 32 are locked — the bot seals closed issues after seven days. Nobody can comment, react or reopen. Demand cannot accumulate anywhere, because every place it accumulated is sealed. Each new requester finds locked threads, opens a fresh one, and the stale bot closes that too. The loop has run 31 times.
I expect the duplicate detector to flag this issue — it already flagged #41199 while I was drafting. That flag is correct on similarity and wrong on consequence: #41199 is closed and locked, as are 29 others. Closing this one against them discards the request for the 32nd time rather than consolidating it anywhere. If this is closed as a duplicate, please close it against a live issue, or reopen the target.
Why it should be cheap to build
- The data is already collected and already keyed by project — project_path is a top-level field on every session-meta/*.json.
- The change is a filter predicate at load time, ahead of sampling and facet generation. Nothing downstream needs to know.
- No schema change, no migration, no new collection, no new storage.
- Strictly additive and opt-in.
I would send a PR instead of an issue if there were source to patch
/insights lives in the compiled binary; this repository carries no source for it (a code search for session-meta returns nothing, and the published mod API in mods/types/claude-code.d.ts does not mention insights). So the change cannot arrive as a pull request from outside, which is why it arrives as an issue with the field, the predicate and the numbers attached — everything short of the diff.
The primitives a scoped run needs are all present in the mod API already published here: $.session.root(), $.fs.list / $.fs.read, command.register / command.run with args, and model.complete / agent.spawn for narrative. If a reference implementation as a mod under mods/ would help, I will write one and attach it to this issue. This answers the question asked on #41199 in April and never answered — I am asking it again, and I am willing to do the work.
Related open bug
#85500 /insights counts subagent sessions as the user's own, inverting the conclusion) is the same root cause: the corpus is not scoped to what the user is asking about, and the report draws confident conclusions from the wrong population. A scope filter plus a visible in-scope session count in the header would help there too.
Environment
- Claude Code 2.1.278
- Linux (Ubuntu LTS), bash under tmux
- 4,294 session-meta records (945 substantive); 634 project paths (50 real, 158 worktrees, 426 /tmp)
- Latest report header: "4,956 sessions total · 490 analyzed · 6,764 messages · 2026-07-15 to 2026-09-19"
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating the /insights CLI command and the session-meta loading path; verify where project_path is read, sampling occurs, and facet/report generation begins. The work is done when bare /insights remains unchanged, scoped paths use the requested prefix behavior, and the report communicates its scope and in-scope session count.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- analytics, cli
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100