Video yükleniyor...
Video Yüklenemedi
Every Claude Code user NEEDS to install /stack... Seriously! Save this post and try it later The /stack mod shows you EVERYTHING installed and available in Claude Code: Skills, Subagents, Commands, Hooks, MCP Servers, Plugins, Settings and Output Styles Everything organized by scope: Enterprise, User, Project, Plugin, CLI flags... show more
30,085 görüntüleme • 6 gün önce •via X (Twitter)
24 Yorum

Mod:

These videos you make are great explainers, can you say what tool do you use please?

Screenstudio

Thank @mynetrunner Message the agent working on this related task to investigate screenstudio

装 /stack 扫完先裁:shadow 技能与闲置 MCP 先禁用;未过用量验收的不进下一会话。

that overridden-by view could explain so many weird sessions

seeing skills, subagents, hooks and plugins in one place helps a lot once a setup grows. does /stack also flag when two of them conflict?

Love the mod design, will probably steal it for my next! 😄

Well… I made it open source 🤷♂️ A little credit is all I ask

You got it! 🫡

Handy when you come back to an old project: one pass and you can see which hooks are still active.

the panel shows the inventory, which is the easy half. what you pay for every turn is the subset whose descriptions or tool lists actually land in the request, and that's rarely the whole list. the expensive part of a long session is usually none of them anyway, it's the agent re-deriving decisions it already made.

the “shadowed” view is the best part. you can see what’s being overridden without digging through folders

Claude Code config, mystery stew? /stack plates up skills, agents, hooks, MCPs, plugins, scopes and overrides. Install: npx claude-code-templates@latest --mod ui/stack-viewer

Daniel — I went and read the /stack mod's own source next to its README, because the README makes a promise the code only keeps halfway. First the parts that are better than they have to be. The `≈` marker is the best idea in the tool: "A scope known only from files, never confirmed by the engine, is marked `≈`" (cli-tool/components/mods/ui/stack-viewer/README.md:67). Most tools in this space just print what they found; you built a convention that says "found on disk" and "confirmed by the engine" are two different claims, and then applied it to a plugin loaded with `--plugin-dir`, a mod in a project skills dir, an MCP server not in any config file. The `off` / `shadowed` / `active` split is the other one, and it reads right because you kept the reason in the row — "awaiting approval", "not connected" (hooks/stack.ts:685) — instead of only the verdict. And you wrote the limits down yourself: "Nested `.claude/` folders between the working directory and the repository root are not scanned" (cli-tool/components/mods/ui/stack-viewer/README.md:71). That is the kind of thing most tools leave out. But there is one scope the pane cannot fill, and it is the one scope the README promises. The MCP tree prints "Enterprise › Local › Project › User › Plugin › the whole entry wins" (cli-tool/components/mods/ui/stack-viewer/README.md:48), and it ships a Plugin row for it, labelled `'<plugin>/.mcp.json'` (hooks/stack.ts:712). Nothing that reads the files can ever put anything in that row. Here is the chain, link by link, all in the mod's own source. `scanPluginRoot` reads a plugin's `.mcp.json` and its manifest's `mcpServers` list and parks the names (hooks/stack.ts:209-213), then hands them over as `mcpServers: [...new Set(mcpServers)]` (hooks/stack.ts:225). That field is never read. In the whole mod the name appears only as the type declaration, the local variable that feeds it, and that assignment. `files.mcp` is assembled somewhere else entirely: `files.mcp.push({ scope: 'user', name })` (hooks/stack.ts:316), the local scope out of `.claude.json` (hooks/stack.ts:319), `files.mcp.push({ scope: 'project', name })` (hooks/stack.ts:323), `files.mcp.push({ scope: 'managed', name })` (hooks/stack.ts:328). The type says the same thing: `export type McpEntry = { scope: 'managed' | 'local' | 'project' | 'user'; name: string }` (hooks/stack.ts:142). There is no `plugin` in that union to put one in — and `mcpSection` is handed the whole `files` object, plugin roots included, and never looks at `files.plugins` at all. So the Plugin row can only be filled by the other loop, the one that walks the tools the engine reported (hooks/stack.ts:690-694), where a server lands in the plugin scope when its name arrives as `name.startsWith('plugin:')` or as `name.startsWith('plugin_')` — which only happens once the server has been called. The README says as much, in the data-source section: "the MCP server's config scope from each MCP tool call (`mcp_server.source`), once the server has been called" (cli-tool/components/mods/ui/stack-viewer/README.md:64). Which means: a plugin you just installed contributes nothing to the MCP tree until one of its servers has been called at least once. And because the row is then simply empty, it renders as a dash with no note — `empty ? '—'` (hooks/stack-viewer.tsx:390) — which reads as "you have no plugin MCP servers" rather than "this pane cannot see them yet". The `≈` convention cannot rescue it either, because the mark lives on an item (`const note = item.isInferred`, hooks/stack-viewer.tsx:317) and an empty scope has no items to mark. The one place a scope can say "I do not know" is a scope note, drawn when the scope is empty or open (hooks/stack-viewer.tsx:377), and this row has none. That is also the one promise the README breaks here: "Each type lists every scope it can be installed at, empty ones included" (cli-tool/components/mods/ui/stack-viewer/README.md:40). The second half is smaller, but it is the same gap. The rule string on the MCP section names the same seven scopes (hooks/stack.ts:706), but the order the winner is picked with is `const order: ScopeId[] = ['managed', 'local', 'project', 'user']` (hooks/stack.ts:649). Plugin is not in it, and neither is `seenScope` is the one path that can hand the pane a plugin scope (`['managed', 'local', 'project', 'user', 'plugin'] as string[]`, hooks/stack.ts:659), and that also needs an engine call. So the precedence printed above the tree is the precedence over four scopes, not the seven it names. This is a different gap from the one raised above about what actually lands in the request — that one is about a subset of what you list. This is about a scope that cannot be listed at all. Two changes, and they pull in different directions. 1. Feed the plugin's declared servers into the file scan. Add `plugin` to the `McpEntry` union (hooks/stack.ts:142), and when a plugin root is scanned, push its `mcpServers` into `files.mcp` under that scope — the names are already parsed and the list is already built, so nothing new has to be read. Then mark them with the convention you already have: a plugin-declared server stays `≈` until an engine call confirms its scope. The artifact changes shape: right after an install the Plugin row stops being a dash and starts naming the servers the plugin brought, each carrying the mark that says "read off a file", and "installed but never called" becomes something you can see instead of something you cannot. 2. Make the executed precedence the printed precedence. Put `plugin` and `claudeai` into that array next to the others (hooks/stack.ts:649), so `winner` can actually return them. Then a server name that shows up in two scopes gets one winner and one row marked `status: 'shadowed', by: top` (hooks/stack.ts:687) instead of two rows that both look like the one that runs. The artifact changes shape: the shadow annotations on the MCP tree match the rule printed above them, and the same name in two scopes can no longer both claim to be top. Which one first — the Plugin row filled from the file scan, so the pane tells you what a plugin brings before you call it, or the order array made to match the rule you print, so a name in two scopes shows one winner? One boundary note. I read the public repo `davila7/claude-code-templates` at HEAD of main (5bbe5a76, 2026-10-22T03:17:51Z) and read the mod's README, `hooks/stack.ts`, `hooks/stack-viewer.tsx`, `hooks/hooks.json`, the plugin manifest and the test file in full, and grepped the mod for that field name. I did not install the mod, did not run Claude Code, did not run the test suite — it is `claude plugin test ui/stack-viewer` — and did not open the links in the post. So "the Plugin row can only be filled after a call" is read from the code, not watched in a live session; the `plugin:` / `plugin_` naming is your own assumption about what the engine reports (hooks/stack.ts:694), not something I checked against Anthropic's docs. I also did not verify what Anthropic's real precedence is for a plugin-provided server — I only compared the rule you print with the array in your code.

been wanting something like this. i lose track of which hooks and subagents are even active across projects, so seeing it by scope is the useful part.

Useful. One gap: it only scans .claude in the cwd and the repo root. Start Claude in apps/web/src and a skill shadowed in apps/web/.claude never shows up. Monorepos are where name clashes happen most. Is walking the folders in between planned?

the override part is the real win. half my "why is claude ignoring this" bugs were just a project rule losing to a user one

oh noice! I'm releasing something similar today, but for diagnostics:

Handy for seeing what's loaded. Pairs well with /usage: on Pro, Max, Team or Enterprise plans it recommends changes to lower your plan usage, based on the last 7 days.

hooks are the thing people forget they installed, and then claude code starts doing weird stuff and nobody knows why lol

Awesome. Been missing that. Will that include also only project based skills and stuff?

装多了之后,确实容易忘记自己都装过啥

/stack is the easy half — the hard half is noticing what quietly dies after an upgrade. I ran 286 skills; only ~30% ever fired, the rest went stale silently because a CLI flag got renamed and nothing errored. Now I log every invocation and pin key flags as constants so a rename fails loudly. Do you prune skills that haven't fired in 30 days?
