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 linemanet 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 updateMANPATHto point at them) - generate section TOCs with
aproposand 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.