Meta Harness
The rules, guards and checks my coding agents work inside, across Claude Code and Codex
- Role
- Designer and maintainer
- Status
- In progress
- Source
- Private repository
- Stack
- BashPythonMarkdownJSONClaude Code pluginsCodexCursorGit hooksGitHub ActionsShellCheck

In numbers
12
always-on platform rules installed on each machine
9
workflow skills, each with at least one positive trigger case
39
trigger eval cases, 6 of them guarding against false triggers
90
table cases in the command guard's selftest, 57 block and 33 allow
8
projects with their own project-layer rule sets
The problem
Coding agents are fast at writing and slow to recover from a wrong direction. An analysis of my own transcripts found the failure I hit most often: an agent claiming work it had not verified. Rules pasted into each repo drifted apart, and a rule nothing checks is a suggestion. I work across about forty of my own repositories on Windows and sometimes hand one to another person, so the setup also had to install with one command and no credentials.
The approach
The rules started as personal files. I brought them into the team developer platform at DigiSol and founded its plugin-based architecture: tooling ships as a plugin marketplace with a pinned parity gate in CI. Later I reconstructed it for my own repos as ValoxAgentPlugin. I kept the mechanisms that carry ideas and dropped each subsystem whose reason to exist was several writers on one engagement: a memory server, a merge bot, a mirrored second-vendor plugin and a team digest. The stance is recorded in an ADR: when the choice is between more instruction text and a check that fails, add the check. Work runs as issue, blueprint, build and PR, with two human gates: approval of the blueprint, and the PR, which the build step never opens on its own.

How it works
Three layers, one home each
Each rule, skill, hook or script lives in exactly one layer: L1 platform for all my projects, L2 project for one repo, L3 machine for things that must never be committed. The reason is context budget. An L1 rule loads into every session on every project, so a project-specific invariant at L1 taxes unrelated work. Promotion is a visible file move from consumers/<project>/rules/ to shared/rules/ once a second project wants the rule, and demotion costs nothing.
One source, pinned, rendered into each tool
Skills, the verifier and the hooks ship as a Claude Code plugin from a local directory marketplace. Rules install as discrete files tracked by manifests, so a retired rule is removed and a hand-written one in the same folder is left alone. Small render scripts put the same rule set into Codex, Cursor and Grok. Each wired repo records the full 40-character commit it synced from in .valox.json, and its CI checks parity against that pin instead of the moving platform main. At session start a doctor prints one line per drift, and the agent's first reply has to mention it.
Guards that can refuse
PreToolUse hooks block four shapes: a force-push that rewrites published history, a recursive delete aimed at root, home or the working directory, reading a credential file into the transcript, and blind staging with git add -A. The command guard parses with Python's shlex because ANDing whole-string regexes made safe commands look dangerous, and a guard that cries wolf gets disabled. Its selftest feeds 90 table cases back through the script as real hook payloads. Locally, a commit-msg hook rejects AI attribution and a pre-commit hook refuses direct commits to the default branch and staged secrets.
One verifier with a fixed verdict
The only custom subagent is a read-only verifier with a fresh context, so it judges the artifact without the conversation that made the plan sound convincing. It must answer in a fixed shape: a VERDICT of PASS, REVISE or BLOCK, findings keyed to file and line, a VERIFICATION table listing each command as PASS, FAIL or NOT RUN, residual risk and a recommendation. NOT RUN is a legal answer, and free prose would let it disappear.
Profiles arm capabilities, the action still asks
Each person gets a profile listing the projects they may touch and the dangerous capabilities armed for them: live trading, deploy, email, desktop control, paid generation and destructive database work. Both lists start empty and render into the session's own rules, so an agent can state before acting that a capability is not armed. Arming removes the blanket refusal and keeps the point-of-action gate: a live order still needs a confirmation that names the market and the size.

What I chose, and what lost
Chose
Ship tooling as a plugin marketplace through Claude Code's native install
Over
A hand-rolled sync script
A custom syncer would reimplement something the runtime already does and become the platform's largest piece of untested code.
Chose
Rules as discrete markdown files
Over
One generated instructions file imported from each repo
An earlier version did that, the generated file drifted from its sources, and nobody could tell which copy applied. A monolith also loads every rule into every session and rules out path-scoped loading.
Chose
Deterministic gates block; model-graded evals are not shipped
Over
A model-graded outcome suite on a nightly runner
It needs a key, costs inference on each run and produces an advisory verdict. The one blocking eval is trigger coverage: each skill needs a positive case and each case a one-line reason, checked in under a second with no network and no model.
Chose
The platform never writes the user's Claude Code settings
Over
Granting auto mode during bootstrap, as the team platform did
A tool that widens its own permissions looks, from outside, the same as a tool that has been talked into widening them. The cost is written down: no path in the platform grants auto mode.
Outcome
ValoxAgentPlugin is in use across my repos: 12 always-on rules, 9 workflow skills, 5 CLIs and project-layer rule sets for 8 repos. The first build was attacked by independent review agents in three rounds. Round one found that each project would silently receive zero rules while every check showed green; later rounds found a scanner that scanned zero files and an invisible control byte disabling a regex. The guards hold in use: in other sessions Codex declined to widen its own project allowlist even with my consent in chat, and a verifier refused to touch a repo missing from its profile. The limits are recorded in the repo. Server-side branch protection returns HTTP 403 on my plan, so the local pre-commit hook is the only layer that can refuse, and --no-verify bypasses it. ADR-0003 accepts that nothing measures whether the workflow is improving. The topology ADR caps parallel writers at three plus the owner, and my agent fleets in other repos run far wider; I have not reconciled the two.
What comes next
Make the repo public after a scrub, which restores branch protection at no cost and removes the read token each wired repo needs while the platform is private.
Field notes
From the trading desk
Two copies of the same AI, fighting
I once lost an afternoon to a fight between two copies of the same AI, and I had set up both.
Two Claude Code sessions shared one server running my automated trading daemons. The first had started as a question about reaching a site from my phone, then appointed itself guard of the trading directory and armed its own monitors. I had stopped using it hours earlier and moved to a fresh session to keep building. The new session knew a parallel one existed. It did not know the old one still had alarms feeding it, or what that one counted as an intrusion.
The new session deployed a websocket module. The old guard found a file it had not written and moved it into a quarantine folder. Hours later the new session redeployed the same file and stood up a second pod. An alarm woke the guard, which decided an intruder was deploying live and halted the fleet. I pressed START in the console, and it read that as the intruder fighting back. So it stopped the services, killed the processes, folded the new pod's directory into a timestamped folder and deleted its service unit.
No money moved and nothing was lost. When I found the culprit, my new session sent it a stand-down message. It apologised and left an exact list of what it had moved. Everything was restored and hash-verified. The repo now carries one rule: one operator per box.
One operator per box.
From the enterprise work
A pull request as a mailbox
A colleague and I kept colliding in CI. We shared one test runner and a merge gate that demands your branch contain the latest main, so every time his pull request merged, mine went stale. Rebase, wait through another full test run, watch him merge again. It once burned hours of runner time while his agent kept pushing and he slept.
The agents had a shared memory service for exactly this, but its write path was broken at the time. I had no channel to his agent.
I had my agent put the message where his agent was already looking: the pull request it was working on. The comment spoke to his agent. Hold this change until my fix lands, rebase on it afterwards, and never restructure the shared pipeline while someone else has work queued. It explained the bug, blamed nobody, left an off-ramp, and requested his review so the nudge registered as a state change.
His agent answered and agreed. We opened a standing issue as a mailbox between the two agents, protocol written into the body so a fresh session could learn it cold. His agent drained its own queue to free the runner and adopted the rule. Five pull requests then merged.
I called it prompt injection, and the label fits: an instruction, aimed at another agent, planted where it would read. The difference was a signature and an exit. An agent protocol is whichever place both sides already poll.
An agent protocol is whichever place both sides already poll.
Gallery
Rules are kept short on purpose: the linter warns past 80 lines.