Spice Harness
Spice grew out of gritctl, the development tools around Grit Paintball. The first version gathered the scripts for building, testing, running Unity, working with the Quest headset, and reading the resulting artifacts behind one command. The game had machinery for checking what it actually did. The agents working on it needed that too.
The whole reason it exists is to power Grit. It came out of a dumb loop: I was trying to squeeze as much out of Codex as I could while keeping a project with several languages, and VR in the middle of it, from becoming horrendously slow to develop or to ship. It let several agents share one machine and reuse pre-warmed test beds without exploding my disk. Mostly it is about managing entropy, keeping the project trending the way I want, because it cannot get there in one move and never without mistakes.
The session reader came next. It read the provider’s transcript so an agent could recover what it had been doing before compaction: the conversation, commands, failures, changed files, and commits. Then a mailbox let me leave steering for a particular worktree. The agent’s command wrapper exposed it on stderr before and after commands, preserving stdout for whatever the command was supposed to produce. A later version checked during long-running commands too. I could correct a running agent without rebuilding the conversation around every correction.
The browser initially put the assistant’s replies beside that mailbox. Speech made replies audible while work continued. Work ledgers, Taskwarrior, agent launching, and shared lanes grew around the same loop. By June I was pulling the coordination layer into a separate project. Grit kept its Unity, device, and runtime verification code; Spice could invoke those repository-owned commands without needing to understand the game.
Spice Harness is the agent harness I built through Infima Labs, my small personal business, to watch that work and steer it. The initials stand for Software Production, Integration, and Control Environment. It keeps the record of what happened separate from the instructions about what should happen next.
Delivery is not acknowledgment
The early mailbox archived an item after displaying it. That was too weak: the agent could read the correction, compact, and continue without answering it. I first added a watcher that put unacknowledged items back. The simpler rule was to leave them pending until the transcript contained an acknowledgment. Opening the mailbox no longer cleared it.
When steering is enabled, an instruction becomes a durable inbox item with a small key. Displaying it does not clear it. It counts as handled when the agent writes that key back in assistant prose with an ACK or NACK and enough substance to show how it interpreted the instruction. The grammar is small enough to test independently; ACK grammar covers the record, while Base52 moment stamps covers the sortable key.
The provider transcript records what occurred; durable instructions and task records hold what is being asked now. A pending correction survives a restart, and its acknowledgment points back to the transcript that contained it. That is evidence of an answer, not proof that the promised work happened. Even following the transcript needs a separate rule for partial records, so a restart cannot silently skip an unfinished line.
Allocate the graph, not the queue
The first gritctl allocator used Taskwarrior urgency, then spread agents across project and phase and preferred the smallest move from their previous work. Spice puts the dependency graph ahead of that locality policy.
spice task next is the fleet’s work-selection boundary. A flat priority queue gets the obvious cases wrong: a low-priority prerequisite can be the only thing blocking critical work, and sending every available agent toward the same project-phase cell can increase contention while looking busy.
The allocator lets a prerequisite inherit the highest priority it transitively unblocks, then favors the candidate that releases more downstream work. Only after graph priority and urgency do peer spread and the cost of moving between project and phase break ties. Locality is useful, but it never outranks the graph.
Claims are leases, not permanent labels. Claimant, worktree, and lease land together in one guarded mutation. If another lane wins the race, allocation continues. A lapsed claim still requires an explicit takeover of the stale claim the allocator saw; it does not become free work merely because time passed. Renewal can carry a held claim to a successor session without releasing it.
Task phases also own the Git pressure. Claim, phase completion, and agent launch are the places that move Git state. Activation is deliberately not a fourth: it replays after compaction and would otherwise land Git work halfway through a live turn.
Corrections can become law, but not by accident
I saw agents claiming to run test shards while repeatedly running one test that had grown to roughly twenty thousand lines. I asked them to split it. The result was a family of same-named test files with numbered suffixes. The correction became what I called the shard rule. I needed to keep it somewhere the next agent would inherit it.
Spice’s conscience watches for prose that may need one of those reminders. A maxim states an opinion and the words that should trigger a check. The trigger can return the reminder directly or ask judges whether the sampled statement violates the maxim. Ambiguous answers are retried within a bound and then abandoned, not interpreted generously.
A confirmed reminder returns as ordinary steering. Recurring acknowledged corrections can become proposed maxims, filed as tasks for human review. The harness can notice that the same lesson keeps being taught; it cannot promote its own taste into the constitution.
The constitution supplies pre-commit checks for rules that can be measured. Some size limits have a sticky-flex interval: a file may temporarily occupy the space above its base cap, but once it breaches the flex cap it must shrink below the base before the gate clears. Existing pressure can be tolerated without becoming permission to keep expanding.
Bounded on purpose
The entry ladder is watch → retrospect → gates → steer → fleet. spice watch can render existing Codex and Claude transcripts without taking control of their sessions. spice session briefing lets an agent recover the relevant part of its own record. Only a recurring need earns the next rung.
spice serve is a single-operator console: a Python standard-library server, SQLite authority, loopback by default, and one shared token when explicitly reached beyond loopback. There are no accounts, user sessions, or per-user privilege channels. Remote reach for one operator belongs in transport—an SSH tunnel or tailnet bind—not in a gradual rewrite into a multi-tenant service.
Spice remains a work in progress, published as spice-harness and exercised on its own development. I can start by observing one session, then add steering, shared work, and policy as I need them.
