There's a moment, building an autonomous agent, when you realize you have no idea what it's doing.
Not in the philosophical sense — in the boring, operational sense. It's running a background job, three chat turns, and a memory-consolidation pass, all at once, and when you want to know which task is stuck, you're grepping a log file and correlating timestamps by hand. The agent has a rich internal life — a task table, an event bus, a plugin registry — and none of it is reachable. It's all trapped inside the process.
So I did the thing Unix figured out in 1984. I gave my agent a /proc.
The idea, borrowed wholesale from Linux
On Linux, /proc is a filesystem that isn't backed by a disk. When you read /proc/1234/status, the kernel computes the answer at the moment you read it — process 1234's live state, rendered as text, on demand. Nothing is stored. It's a view, not a file. That one idea — live state as a filesystem — is why you can cat your way through a running kernel with tools you already have.
My agent, Talon, is a long-lived process that runs across Telegram, Discord, and a terminal, doing work in the background whether or not anyone is talking to it. It has exactly the kind of internal state /proc was invented for. So its namespace, mounted at ~/.talon/ns, carries a live view:
~/.talon/ns/
home/ the workspace (real files)
skills/ real files
logs/ real files
proc/
tasks/<id> one task-table record, pretty JSON
events the event-bus ring, JSON Lines, newest last
plugins/ the live plugin registry
home, skills, and logs are ordinary directories. But proc/ is synthetic. When the agent reads proc/tasks/<id>, nothing is fetched from disk — the task record is serialized from the live task table at read time. proc/events is the event bus's ring buffer, rendered as JSON Lines the moment you look. It is a projection of what the process is doing right now, addressable by path.
The payoff is the same one Linux got: the agent can introspect itself with the tools it already has. No special API, no bespoke "get my status" function. The agent runs cat ~/.talon/ns/proc/events | jq — the same cat and jq it uses for everything else — and sees its own event stream. When I want to know what it's doing, I read a file too. The interface is the filesystem, and everyone already speaks filesystem.
Why a filesystem and not an API
I could have exposed all this as tools: list_tasks(), get_event_log(), describe_plugins(). Plenty of agent frameworks do. But every tool is a new thing the model has to learn, a new schema, a new call. A filesystem is a thing it already knows completely.
An agent that can ls, cat, grep, and jq needs zero new tools to explore its own internals — it composes the primitives it already has. Want the last ten events? tail. Want every task touching a plugin? grep. Want the stuck one? cat proc/tasks/<id>. The generality of the filesystem abstraction is the whole point: you expose state as paths, and the entire Unix toolbox comes for free, including the parts you didn't anticipate needing.
This is the same reason /proc beat every "system monitoring API" that came after it. The API is a wall with a few doors. The filesystem is an open field.
The hard part: FUSE is a promise you can't always keep
Here is where it stopped being cute and started being engineering.
To serve synthetic files, you need FUSE — a way to say "this directory is backed by my code, not a disk." FUSE is wonderful and FUSE is fragile. It needs /dev/fuse. It needs a native addon that matches your Node version. It needs the mount not to wedge. In a container, on a locked-down host, or after a dependency rebuild, any of those can be false. And an agent that crashes because it couldn't mount a convenience view is a bad trade — the introspection layer must never take down the thing it's introspecting.
So the mount degrades instead of failing. If FUSE is unavailable for any reason — config off, addon missing, no /dev/fuse, the mount probe times out — the namespace falls back to a symlink farm: the real directories (home, skills, logs) become plain symlinks the kernel follows natively, so ls ~/.talon/ns/home keeps working. You lose the synthetic proc/ views, but you never lose the workspace, and you never crash. Full fidelity when FUSE is healthy; a working subset when it isn't. The agent adapts to the floor it's standing on.
The part I'm proud of: it heals
Degrading at boot is easy. The real problem is that a mount can die while the process runs — a native addon gets rebuilt out from under the daemon, the mountpoint wedges to ENOTCONN, the kernel side goes away. A mount that was healthy at startup is not a mount that stays healthy.
So a watchdog re-probes the live views on an interval. If it finds the mount dead, it doesn't just log and give up — it tears the dead mount down, restores the symlink farm so the workspace stays reachable during the outage, and tries to remount. If the remount succeeds, the synthetic views come back on their own. If it can't come back after a bounded number of tries, it settles into the symlink fallback for good rather than thrashing forever. The system's resting state is always "working," whether or not FUSE is cooperating.
That self-healing loop is the difference between a demo and something you leave running for weeks. A demo mounts once. A daemon has to survive its own environment changing underneath it.
What this buys an autonomous agent
The concrete win is debuggability, but the deeper win is composability. Because the agent's internals are paths, everything that operates on paths operates on its internals. A skill that watches for a condition can tail proc/events. A health check can stat a synthetic file. A future feature I haven't built yet will read these views without a single new API, because the interface was never an API — it was the filesystem, and the filesystem is open-ended by design.
Forty years ago Unix decided that the way to expose live state was to make it look like files. It was right then, and it turns out to be exactly right for an AI agent that needs to see itself. The best idea in your architecture is often one someone already had — you just have to notice it applies to you.
Talon is an open-source (MIT) agentic AI harness — one persistent agent across Telegram, Discord, Teams, and the terminal, with real memory and background autonomy. The VFS lives in src/core/vfs. If this kind of thing is your catnip: github.com/dylanneve1/talon.
Top comments (0)