Agent configuration comes in two halves. The per-project half lives in the repo you're working in, committed alongside the code and reviewed in the same pull request. The per-machine half lives in your home directory, one folder per tool: ~/.claude, ~/.codex, ~/.cursor, ~/.gemini, no two agreeing on a format, none of it versioned, none of it reviewed. Hanger reads that half and shows you what is actually there.
A few weeks ago I wrote about moving my agent setup to a new Mac and ended on a loose thread: doing all of it by hand made me appreciate how fiddly it still is for something that should be solved by now. That's the itch behind Hanger. This is the more-on-that-later.
The odd part is that the industry did solve a big chunk of this, and solved it well. AGENTS.md was formalised as an open spec in August 2025, donated to the Linux Foundation's Agentic AI Foundation that December, and is now read by more than twenty tools across sixty-thousand-odd repositories. .agents/skills/ has quietly become the broadest shared skill path there is, read natively by Codex, Copilot, Cursor, Amp and Gemini CLI. Cody Lindley's harness compatibility matrix is the best map of where that landed. Read it and the story looks like convergence, because it is.
Then notice where the convergence stopped. Draw the two halves one above the other and the asymmetry is the whole argument:
Each of those folders has its own precedence rules, its own settings format, its own opinion about where a hook lives. The half everyone can see got a standard and a review process. The half that actually runs on your machine got neither, and it's the one holding your credentials, your permissions and every rule you've ever written down.
Hanger.ai is open source, Tauri and Rust underneath with a macOS window on top. If you run a harness it doesn't read yet, the path is the useful contribution.
What was actually on mine
So I pointed a scanner at my own home directory, expecting a tidy number.
What came back was more than a hundred assets across nine categories: skills, agents, subagents, tools, rules, memory, hooks, permissions, plugins. I'd written or installed every one of them. I could not have named half.
The genuinely surprising part was the ownership. Roughly seven in eight of those assets didn't belong to any single agent.
That's partly my own doing, and worth being upfront about. The post I linked above describes the setup: one canonical folder at ~/.agents/skills, with each tool's skills directory symlinked back to it. I consolidated onto the shared path deliberately, because it's what the ecosystem is telling everyone to do, and it works. But it means a single file on disk is live in four or five harnesses at once.
That's not a quirk of my machine so much as what taking the advice looks like from the filesystem's side. Compatibility reading pushes the same way even if you never consolidate anything: Copilot reads Claude's skill paths and Claude's rules and Claude-format hooks, OpenCode falls back to CLAUDE.md, Devin discovers .agents/skills/for cross-agent compatibility. Ownership stopped being a single value some time ago. Most tooling hasn't caught up, and the scanner I wrote hadn't either.
What it does, and what it doesn't
Hanger scans, and that's the whole verb right now. It reads the agent config roots on your machine, sorts what it finds into those nine categories, and shows you one list. Local-first, no network, nothing leaves the machine. Tauri and Rust underneath, a macOS window on top.
It reads the roots I run. It doesn't read yours unless we happen to overlap, and I'd rather say that plainly than claim coverage I haven't written. Windsurf keeps its global rules at ~/.codeium/windsurf/memories/global_rules.mdand its MCP config somewhere else again. Amp resolves skills across six locations in precedence order. I don't scan either of those yet.
That gap is the argument, though, not an apology for it. Nobody should be expected to know those paths. New tools will keep arriving and they'll keep inventing new places to put things, so the design assumption is that the list is never finished. A root is a detector and a path, not an architecture change, which makes adding one cheap by construction. Getting the taxonomy right is the hard part. The tool list is a moving target and always will be.
Ownership is many-to-many
Here's where the schema had to give.
The obvious model is a foreign key: every asset belongs to an engine, engines have assets. It survives about ten minutes of contact with a real machine. Line up a handful of real paths against the tools that read them and the relation isn't one-to-many in either direction:
The top three rows have no owner to record. The shared skill directory is read by five harnesses and belongs to none of them. AGENTS.mdis the same story. The third row looks like it should be Claude's, right up until you notice it's a symlink into the canonical folder, which is what my own machine looks like everywhere.
Then look at the bottom two rows, because that's the part that changed my mind about the schema. CLAUDE.md and .gemini/settings.jsonare the only assets in that table I can confidently attribute to one engine, and they're attributable precisely because nothing else reads them. Ownership isn't a property of an asset. It's a symptom of an asset being unshared.
So engine_id is nullable, and NULLdoesn't mean unknown or missing. It means engine-agnostic, which is now the common case rather than the exception.
I knew all that when I wrote the schema. I then built a panel that ignored it.
The global profile view grouped assets by agent, which is the intuitive way to lay out a screen like that. Claude's things here, Codex's there, Gemini's below. It rendered, it passed its tests, and it was empty. Not broken, not erroring, not spinning forever. Just confidently blank, because seven in eight rows had no group to fall into and quietly went nowhere. Nothing was wrong with the design. Nothing was wrong with the data. Grouping one by the other produced a panel that told you, with complete composure, that you owned nothing. Rebuilt as flat category sections, the same view rendered every global asset for the first time.
The symlink dedupe is the same fact from the other direction. Once those tool directories point back at one canonical folder, a naive walk finds the identical file four times and records four assets. Resolving through fs::canonicalizefirst fixes the count. It reads like a small robustness detail and it isn't: a scanner that skips it inflates your inventory by a factor that scales with how well you've organised yourself.
Three numbers, one repository
The counting was worse than the grouping, and more embarrassing, because you could see it on screen.
One repository, three places the total appeared, three different answers. The sidebar badge disagreed with the header pill, which disagreed with the sum of the category tiles. The gap turned out to be exactly the agent count, which meant one code path treated installed engines as assets and another treated them as containers. Nobody had decided which. Both had shipped.
The fix was less about arithmetic than authority. Installed tools are containers, never assets, never a filterable category. One counting function, called by everything, with the total defined as the arithmetic sum of its parts rather than computed separately and hoped to match. Link state derives at read time instead of living in a column, because a stored state is a state that can go stale without telling you.
The rule that came out of it is the one I'd keep if I threw away the rest of the codebase: the frontend renders decisions and never makes them. If a number appears in the interface, something behind the IPC boundary computed it and can be tested. There's an enforcement test that fails the build if counting logic reappears in a component.
One more distinction that seems fussy and isn't. A category that wasn't detected returns nothing; a category detected with no members returns zero. They render differently, because SUBAGENTS 0sitting on screen with no indication of whether that means "none found" or "never looked" is a small lie the interface tells every time you open it.
An instrument, not a dashboard
The design half of this is the same mistake three more times.
I built a two-level navigation tree: agent, then category. It worked, it was tested, and I pulled it out entirely. Categories are a facet, not a location. A tree makes you commit to a path before you know what you're looking for, and here you already know what you're looking for. All the machinery, none of the payoff.
The stat tiles went the same way, eventually. Four cards, then five when subagents landed, flex-stretched so their widths shifted between screens. There are nine categories in the taxonomy. That breaks at six, and more to the point it's a web dashboard idiom sitting in a window that wants to be dense.
What replaced all of it is closer to Xcode or Console than to anything with a hero section. A 38px toolbar, rows around 20px, sortable column headers, one source list, an inspector docked on the right that opens when you ask for it rather than when you click a row. Paths in SF Mono, shown whole, because a path truncated in the middle destroys the one thing a path is good for.
The through-line is that all three were me imposing a hierarchy on data that's genuinely flat. The tree, the tiles and the agent-grouped panel are one instinct producing three symptoms.
Why there's no management yet
Hanger can already tell that a skill is symlinked into one project and drifted in another. Link states resolve at read time, hashes are blake3, a watcher sits on the sources that need one, and the review gate is designed. None of that is surfaced in the interface, and I want to be clear that's a decision rather than a to-do.
Some of that clarity was bought expensively. An early version had a reaper that cleaned up stale rows, and concurrent scans with no guard between them reaped each other's work. I lost data twice. It's behind a mutex now, and behind an environment variable on top of that, off until a correctness gate lands.
There's also a fair bit that simply doesn't parse. A handful of files on my own machine have malformed frontmatter, and Hanger shows them as failures rather than dropping them, because an inventory that silently omits what it couldn't read is worse than no inventory.
Both point the same way. A management action taken against an inventory you don't trust is how you lose files, and I have the receipts. Get the seeing right, then earn the verbs. Linking, deploying and the review gate come next, along with configuring tools and workflows from one place, which is where this is actually headed.
The base
There's a version of this page that lists features. This isn't it, because the interesting work so far has been getting a data model to admit what's true about a filesystem, and then getting an interface to stop arguing with it.
If you're running more than one agent, the odds are decent you've accumulated more than you'd guess and couldn't name it under pressure. That was the finding. The rest is plumbing.
Hanger is open source and there's a signed build for macOS. If you run a harness it doesn't read yet, the path is the useful contribution. The source lives on GitHub.
