Cameron Boehmer

Elements of a Metaharness

Harness-agnostic skills, prompts, roles, and transcripts

Introduction

If you use multiple harnesses on a regular basis, you've probably MacGyvered (Yegge'd?) some solution to the problems of sharing skills, prompts, roles, transcripts, and other accoutrement of the harness. Each of them can be resolved with a little unix-foo, but coaxing harmony out of a bag of unix tricks is often as much art as science, and I've found that these issues become obligingly tractable when approached through a single entry point, or a metaharness.

What follows is a sketch of how my metaharness, agent, works in my own software factory sweatshop; the ideas are simple enough and my implementation personal and messy enough that I am sharing this merely as a page from my grimoire, not as software ready to eat—though perhaps your agent can help you extract some nutriment from the 1,700 line reference implementation.

One Wrapper to Rule Them All

Wherever I want to run a harness, agent is my entry point. It consults the environment for a variety of values: AGENT_BIN determines which concrete harness to run, AGENT_CODEX_MODEL, AGENT_CLAUDE_MODEL, and AGENT_PI_MODEL select each harness's model, and AGENT_EFFORT specifies thinking levels. Others contain flags to pass to the concrete harness, e.g., AGENT_CLAUDE_FLAGS=--allow-dangerously-skip-permissions.

And the environment values are easy enough to override with arguments. If the environment has AGENT_BIN=claude but I want to run pi, I can say > agent pi. Because agent passes through any arguments it doesn't consume, I can also say things like > agent codex resume (though there is also a cross-harness resume feature).

agent has four core responsibilities:

  • providing the harness with a list of skills
  • compiling the system prompt from a list of candidate paths
  • enabling role adoption
  • standardizing transcript access to support resume and auto-titling

Skills and roles are built on top of system prompt composition, but leaning on man as a replacement for harness skills is my favorite feature, so let's start there.

Skills

man pages are all you need

Skill-sharing and organization was the first thing that motivated agent. Before I stopped using harness-native skills, the major harness formats were largely compatible, and I shared skills across harnesses by symlinking, e.g., ~/.claude/skills to a central ~/.agent/skills folder. While I found the vague threat of format incompatibility tolerable, what I found less tolerable was the restriction of storing skills in one place. Most harnesses have since been updated to support multiple installation locations, but I prefer a single cross-harness pattern over multiple integrations. In my homelab, agents write utilities that are meant for all users and agents, and wiring up each repo to publish skills to a hidden folder in each user's homedir felt wrong. What beckoned was a pattern where skills and docs live in the repo that they describe (or in some cross-repo collection), and a means of exposing them to agents thence.

The Linux manual, familiar to developers from the Before Times as the thing Stack Overflow saved you from, is very nearly purpose-built for this problem, and even offers solutions to a few more, like just-in-time discovery over large sets of skills and docs (as opposed to loading the whole catalog's index into the system prompt), or multi-level organization.

By way of reminder or introduction, man has a few features (and friends: apropos, whatis) that you may not be familiar with:

  • it has nine standard sections—and you can add your own
  • apropos <regex> greps page names and descriptions, prints matches one per line
  • man et al. accept section arguments to limit their results, and some support regex or wildcards in their query strings; crucially, apropos -s X . will print a list of all pages in section X (names and one-line descriptions), which serves as an excellent table of contents (or list of "skills")

There is plenty more to learn about the man ecosystem (glance at man {man,apropos,whatis}), but let's get back to how agent leverages it to implement harness-agnostic skills.

Generating & Installing Man Pages

So, we know it's possible, and what remains is execution:

  • write markdown files to serve as references or guides
  • convert in-repo markdown files to a man-compatible format like mdoc or roff (see Lowdown or Pandoc)
  • install them somewhere on MANPATH (or update MANPATH to point at them)
  • generate section TOCs with apropos and pass them to the concrete harness at invocation

Because this is not a post about NixOS, I will spare you the details and just say that I use a post-install hook in the repo's Nix package build to trigger Markdown-to-roff conversion with Lowdown, and a service that runs after mandb during NixOS activation to generate the TOCs, which are stored in /etc/agent/AGENTS.md.d/man-pages.md.

Prompts

Layering AGENTS.mds via AGENTSPATH

In order to support arbitrary layers of concatenated AGENTS.mds, I conjured AGENTSPATH, a PATH-like variable holding a list of directories (or directory sentinels, default: /etc/agent/:~/.agent/:$gitroot/:.) that agent traverses to generate a system prompt appendix. For each entry, it looks for an AGENTS.md, and also an AGENTS.md.d/, appending all the *.md files it finds therein to the system prompt.

You can imagine how this is flexible enough to support things like skills directories, a role system, and so on.

Roles

I am not a big consumer of roles. I have never been smitten with Yegge-style swarms, preferring to approach agentic development in a stodgy, single-threaded, pair-programming fashion. I initially implemented the roles feature because I had one solid use case (car mode, agent --role mobile, which prioritizes brevity over detail), and it was easy. Recently, it has come in handy as I've begun using a kanban-style card system to experiment with a more product managerial approach to burning tokens, and each card gets an authoring agent and a reviewing agent.

By default, the AGENTSPATH traversal will skip role-*.md files—unless agent is invoked with --role <role>, in which case it will also load role-<role>.md files found in AGENTS.md.d/ directories along AGENTSPATH.

Transcripts

A Few Loose Ends

Last and perhaps least, agent transcripts standardizes access to harness transcripts. This is useful primarily for providing a searchable, cross-harness resume feature agent resume, and also for tailing session transcripts to catch early user messages that can be used to auto-title agent sessions and their owning windows or tmux sessions. There is nothing particularly novel about this; I asked for a cross-harness resume feature (that is, resuming a session in its harness of origin) driven by fzf, and a way to extract the first user message from a session to send to an LLM for title generation (which gets applied to tmux sessions).

Beyond the Metaharness

A Software Sweatshop Workshop

I'm happy with how agent helps me juggle subscription and local inference harnesses without thinking too much about the details of any of them. I go through phases working with different providers and models, and switching between them without having to also wrangle skills, prompts, roles, or transcripts is a blessing.

While the metaharness is useful, it's not the biggest contributor to throughput in the lab. tmux has been central for nearly fifteen years, and I run a session per project, whether that's a new repo, a feature on an existing repo, or something cross-cutting. The tmux session's window processes get exec'd in a kernel namespace that sees a ZFS dataset clone of all the lab's repos so that agents (and all session processes) get identical views of the filesystem, can't step on the toes of processes in other sessions, and can work across repos as necessary. A speculative merge queue allows multiple releases to test in parallel by assuming those ahead of them will succeed (and invalidating those behind them when they fail). A kanban-esque system is helping me move away from pair programming (or micro-managing) and towards product management. And a conventional Makefile per repo makes CI the default, including creating and activating NixOS generations. It's far from perfect, often buggy, and while I've oscillated between mania and feeling like a hamster on a wheel, this year has been the most fun I've had building since I learned to code over twenty years ago.

Postscript

Embedding-based Man Page Search with vapropos

While apropos's ability to surface man pages on the basis of a keyword query is cool, it's limited to regex matching against the title and short description of the page. I wanted more flexible semantic search across the full page contents, so I implemented vapropos, a vector-based alternative. While my agents don't really need it given that my skills and doc indices are not unmanageably large (and still included completely in the system prompt), I still see them use it sometimes to focus in on the appropriate pages for a given problem or circumstance.

If this sounds like the kind of work your team or organization needs, feel free to reach out. I help banks modernize their software and infrastructure as a consultant with PwC, and also offer pro bono advisory conversations to good causes.