Skip to content

Trace grammar

Steven Enamakel edited this page Sep 1, 2026 · 3 revisions

Trace grammar

Coordination in tinyhivemind-hive is stigmergic in Grassé's sense: work leaves a trace in a shared medium, and the trace is the stimulus for the next piece of work. The transcript is the medium. No agent addresses another, and nothing in src/trace/ dispatches anything.

One marker line

!<kind> [#topic] [>target] [^cite ...] [free text]

A marker is recognised only at the start of a line, ignoring leading whitespace, and only outside a fenced code block. Inline backticks need no masking, since a marker preceded by a backtick is by definition not line leading.

!propose #stage Stage the rollout across three regions.
!support #stage ^1 Staging bounds the blast radius if the migration is wrong.
!object >3 The regions are not independent, so this does not bound anything.
!commit #stage

The seven kinds

kind what it does
propose puts a new option on the floor
support adds the author to a topic's supporter set
object silences the advocate of the targeted message
refute caps a topic once enough members argue a cited fact against it
evidence supplies grounds without taking a position
question asks for something the room has not established
commit records the decision after quorum

Note what object does. It names a message, not a topic, and it removes that message's author from the supporter set of the topic they were advocating. That is cross-inhibition, and Episode policy has the numbers on why the asymmetry is load bearing.

refute, and why it is off by default

refute is the mirror of object. Where an objection names a person — the author of one message — a refutation names a hypothesis, and once refutation_cap distinct members have argued a cited fact against a topic, that topic stops carrying however many supporters it has.

!refute #retries ^4 The retry path shipped disabled and has never fired.

It is the only marker that requires both a #topic and a ^cite. Without either it deposits nothing, so every refutation is grounded by construction and a topic can never be capped on an assertion with nothing behind it.

Nothing is deleted. A capped topic keeps its supporters, keeps its weight, and stays in the standings — only carried changes, so the transcript records that the room considered the option and a reader can audit the refutation back to the message it cites.

It exists because the live hidden-profile run found the gap: killing a hypothesis with !object costs one turn per advocate and grows with every new supporter, so a room runs out of budget before it runs out of advocates. The mechanism is the missing α(v) term of the honeybee model this library takes its cross-inhibition from — see Further reading.

refutation_cap is None by default, which means refutations are recorded and cap nothing. The benchmark scored the mechanism and it lost: seven points of accuracy on the simulated task, and more as each member's private read gets noisier, because a refutation is global where an objection is local. A member firing one on a noisy read removes an option for the whole room. The case it was built for — a hidden profile, where one member holds the fact that overturns a decoy — is not what that benchmark measures, which is why the mechanism is opt-in rather than removed.

Reading

let traces = read(&transcript);

read folds a projected transcript into traces in sequence order. A message carrying no marker contributes nothing, so a transcript of ordinary conversation folds to an empty medium. Nothing is coerced into a vote for having been typed in a deliberating room.

resolve handles one body. Passing None extracts from the body. Passing Some, including an empty vector, selects from what extraction found there, which is a deliberately narrower contract than mention::resolve has. There is no host-side resolution step a supplied trace could legitimately carry, so a supplied entry can only name which extracted trace to keep, by its offset and kind. Anything else it claims (a different topic, target, citation, or text) is discarded in favour of what the body actually says, and a repeated offset is rejected rather than selecting the same trace twice.

TRACE_CAP is 16. A body depositing more keeps the first sixteen in reading order, for the same reason MENTION_CAP exists: one message must not be able to grow the fold without limit.

What real models get wrong

Running the grammar against live agent CLIs surfaced four failures the simulation could not reach, and every one of them is a host obligation rather than something the library can impose. Three of the four appear in the published taxonomy of multi-agent failures as well.

Models coin two names for one idea, so support splits across #rollout and #rollout-strategy and never adds up to a quorum. The fix is a prompt that names the options already on the floor, folded through the library's own standings, with each option's supporter count and how many it needs.

Models restate their own last line verbatim, sometimes for four consecutive turns. repetition_cap damps a restated support and cannot see this. The fix is showing a participant its own last line and asking for something that moves the room on.

Models write !commit while the room is still deliberating, which adds no supporter and can burn a whole budget recording a decision that was never reached. The fix is offering only the moves that count in the turn's phase.

Models drop the #, so the line names no topic and deposits nothing. The fix is calling out the sigils explicitly, with a right and a wrong example.

Benchmarks has the full account of those runs.

Clone this wiki locally