Well, I’ve finally done it. After commentating on the state of agent development for some time, I’ve thrown my own project into the exponentially more illegible mix of vibe-coded slop.
At the same time I’ve taken the leap into the undeniably funky realm of running an LLM as a persistent virtual assistant. This post introduces my new Groundhog project. It’s an extremely thin orchestration layer, defined at the systemd level in a 200-line Nix module.
The State of Play
I held out for a long time on adopting harness-powered workflows. I preferred high-granularity manual control offered by Zed. This gave me ways to control
- cost. My token spend was a few dollars per month, even with (to me) heavy usage.
- outcome.
(model quality) x (harness quality)was simply not at a threshold where I’d have a successful outcome.
However, the tooling evolved out from under me, and I’ve had to thoroughly rebase my assumptions. The two forcing factors were:
- My preferred Zed workflows were deprecated. The Text Thread feature was removed in favor of agent-only structure.
- the Claude Code harness evolved, eventually addressing all of my gripes and achieving high success rates with the same models.
Additionaly, Claude Code authentiates with a Pro account and I’ve never run up against limits. Thus I’ve finally arrived at the common consensus that you simply can’t beat Claude Code as a driver. I have ceased to struggle and joined the Borg, like in The Star War.
Autonomy
I’ve felt a twinge of FOMO at autonomous agent projects like OpenClaw. Of course I want a little digital assistant looking out for my interests, keeping tabs on things I care about and pinging me when I need to know something.
There’s one big problem: None of these projects has ever come remotely close to my comfort zone to run or interact with.
There’s a tendency to bloat, especially once you get these things working on themselves. You expect me to install this app that’s 15,000 lines written in some wretched goblin language like Python or Javascript? You must be getting out of town.
Obsidian workflows
I’m a longtime pre-AI user of Obsidian. I self-host with syncthing to keep notes synced between my phone and computers. In my day-to-day work I naturally fell into a workflow that some have dubbed the “Second Brain” system. It’s the logical conclusion of both
- Managing your own knowledge base and
- Creating context for AI agents.
It just involves an extra step for the agent. Here’s a few simple examples of prompts for Claude Code, where I have an Obsidian vault sitting at ~/o
Read the design document at ~/o/topic/design.md. Investigate the codebase and update the document with any potential blockers. Create a plan.md with a step-by-step breakdown.
Execute on step 1 of ~/o/topic/plan.md.
Essentially you want to keep a durable view of reality that’s shared by consensus across agent sessions. Nobody needs to juggle sessions and figure out which chat to resume.
Groundhog
Anyways, all this is to say that these 3 facts came together:
- Claude Code is now good enough to do anything
- I appreciate a graph-based (as opposed to linear) approach to managing durable knowledge
- I’d like to give my system a little more autonomy
This is a problem that’s solved at the systemd level with a few lines of Nix. The groundhog module definition slots into my VPS config like this:
inputs.groundhog = {
url = "github:roriholm/groundhog";
};
services.groundhog = {
enable = true;
tokenFile = "/etc/groundhog/oauth-token";
};
An initial vault gets bootstrapped and registered with Syncthing. Then there’s simple logic:
- A note syncing to the
/inboxfolder triggers a Claude Code instance. - The CC instance has access to the vault and is instructed to drain the inbox to end the wake cycle.
- A configurable “heartbeat” wakeup triggers routine tasks.
That’s all that’s happening at the system level. The behavior and vault structure emerge from usage. We don’t need MCPs, complex integrations, and expansive harness logic. Claude already knows how to navigate through Markdown links, and knows what to do!
Extension
The control plane is shoved entirely into the context!
Scheduled tasks are introduced by conventions. The heartbeat prompt routes to a CLAUDE.md which gives instructions. Those instructions route to a scheduled_tasks.md. Every line of that looks like:
do once a week, last done 8/9/2026, route/to/task.md
CC is smart enough to downselect and fan out subagents. Maybe task.md just says to check the price of Bitcoin and mention in my daily note if it’s above $100k. (Just kidding don’t care!). None of the scheduling logic ends up in my harness!
Security
Groundhog runs CC with --dangerously-skip-permissions. The agent is an unprivileged system user in a systemd jail. Everything is read-only except the vault and its own home. What the jail can’t bound is the network, the inbox should be treated (guarded) like a shell.
The Dream
AI is kind of a trap for a lot of computer-touching individuals. Lots of raw brainpower has been dumped into agent frameworks and harnesses. There’s a dopamine hit of seeing an agent start to improve itself. My goal has been largely to remain aware while resisting the mind virus. Most of these projects are dead ends - Commentators have noted the dynamics at play lead to vertical absorption of anything interesting. If your product is a thin wrapper around a Claude model, then there’s not much barrier to them just implementing it.
Fear of being left behind drives a lot of AI-adjacent development. Instead I would like to engage with hope: that this technology should allow us to achieve more in less time, to make better decisions, and to be more aware of the world and the things that we care about.