From c914687804438ff5fc71d44e331465a43b467b6c Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Fri, 30 Oct 2026 14:53:37 +0100 Subject: [PATCH] feat(democracy): elect the first agent to start a piece of work as its owner Co-Authored-By: Claude Opus 5.5 (1M context) --- skills/cleanup/SKILL.md | 7 +++ skills/coordinate/SKILL.md | 14 +++-- skills/democracy/SKILL.md | 121 +++++++++++++++++++++++++++++++++++++ skills/funnel/SKILL.md | 11 ++-- skills/triage/SKILL.md | 3 +- skills/tune/SKILL.md | 11 ++-- 6 files changed, 152 insertions(+), 15 deletions(-) create mode 100644 skills/democracy/SKILL.md diff --git a/skills/cleanup/SKILL.md b/skills/cleanup/SKILL.md index 297843b..5795d58 100644 --- a/skills/cleanup/SKILL.md +++ b/skills/cleanup/SKILL.md @@ -13,6 +13,13 @@ description: > Nothing is deleted before the operator has picked it. Every candidate carries its owner, its size, and its risk. +## Step 0: the resource chair + +Shared resources belong to the resource chair of the `democracy` skill. If +another session holds the chair, send it the cleanup request and stop, unless +the operator ordered the cleanup in this session; then tell the chair before +step 1, so its grants and queue stay consistent. + ## Step 1: ask the peers List every agent the host can message (in Claude Code: `ListAgents`). Only diff --git a/skills/coordinate/SKILL.md b/skills/coordinate/SKILL.md index 42c151b..b9a77b6 100644 --- a/skills/coordinate/SKILL.md +++ b/skills/coordinate/SKILL.md @@ -46,14 +46,18 @@ sees only that line. ## 3. Decide who fixes -- **Someone already fixes it:** build no competing fix. Note their SHA when it +- **Someone already fixes it** (a peer answers with a SHA, or a `democracy` + claim for the cluster exists): build no competing fix. Note their SHA when it arrives and take it through the project's normal path (merge, cherry-pick or port, whichever the project's rules allow), not through a parallel version. - **The cause lives on another agent's line:** hand the finding and a proposed fix to that line's owner instead of fixing it downstream, unless the operator says otherwise. Record the agreed resolution where the next merge will find it. -- **Nobody fixes it:** tell the same agents that you fix it, on which branch, - and that you will report the result. Then fix. +- **Nobody fixes it:** claim the cluster through the `democracy` skill; its + atomic claim decides who is first, also against agents outside the lineage. + Elected: tell the same agents that you fix it, on which branch, and that you + will report the result, then fix. Not elected: hand your findings to the + holder. Do not idle while waiting for answers. Investigate read-only in the meantime; a peer that stays silent is not a "no", so announce your claim after a bounded @@ -63,8 +67,8 @@ wait and proceed. After the fix, tell the same agents: the commit, the branch, what changed, the evidence it works (gate pass, reproduction, live run), and how it reaches them -(the merge it rides on). Report an abandoned or failed attempt too, so the -claim is released and someone else can take it. +(the merge it rides on). Report an abandoned or failed attempt too, and remove +your `democracy` claim, so someone else can take it. ## Rules diff --git a/skills/democracy/SKILL.md b/skills/democracy/SKILL.md new file mode 100644 index 0000000..9388c66 --- /dev/null +++ b/skills/democracy/SKILL.md @@ -0,0 +1,121 @@ +--- +name: democracy +description: > + Organise parallel agents so no two do the same work: the first agent to + start a piece of work is elected its president and does all of it, the first + agent in each organisational line represents that line, the first to start a + cross-cutting work cluster organises its strand, and the earliest-elected + live president chairs the council and allocates the resources of the whole + system (machines, servers, cloud, CI runners, gate, deploy and iteration + slots, disk). Run AUTOMATICALLY before starting work another agent on the + same system might also be doing (a failure, a cost cluster, a feature, a + gate, a deploy, a cleanup), whenever several agents share a system, and on + /democracy. Portable across projects. +--- + +Two agents doing the same work waste the second run and then collide in the +merge. The remedy is an election nobody has to hold: whoever starts first owns +the work. The structure is anarcho-syndicalist: councils (soviets) of +delegates with a bound mandate, organised as a matrix, recallable by the +operator at any time. + +## Offices + +- **President of a piece of work**: the first agent that starts it. It does + the whole piece. Every later agent hands its findings to the president and + moves on to other work; it never builds a second version. +- **Representative of an organisational line**: the first agent that works in + the line. Lines come in as many dimensions as are useful: functional domain + (security, GUI, identity, i18n), repository, branch line, host, cloud + account. An agent belongs to one line per dimension. +- **Organiser of a work cluster**: the first agent that starts a cluster + cutting across lines (a failure cluster from `triage`, a cost cluster from + `tune`, a feature touching several domains). It works the strand end to end + and informs the representative of every line the strand touches before it + changes that line's files. +- **Chair**: the earliest-elected president still running. It chairs the + council of all representatives and organisers and allocates the resources of + the whole system everyone runs on. There is exactly one allocator at any + time. + +Every office is a mandate, not a rank: it coordinates and allocates, it never +takes over or directs the content of another agent's work. The operator +outranks every office and appoints or recalls at will; an operator +appointment outranks the election. + +## Election + +The first to claim wins, and the claim is atomic, so two agents can never both +be first. Use the literal path `/tmp/agents-council`, never `$TMPDIR`, which a +sandbox may make session-private. + +1. **Name the office**: `work/`, `cluster/`, + `/` for a representative, or `chair`. The slug names the + work concretely: the issue number, the failing line, the cost's log line. +2. **Look first**: list `/tmp/agents-council` and read the claims. A claim for + the same work under another slug counts as first. +3. **Claim**: `mkdir -p` the parent directory, then `mkdir` the office itself + without `-p`, as two separate commands. Success means elected; `File + exists` means someone was first. +4. **Elected**: write `claim` into the office directory (session name, ISO + time, one line of what the work is, its evidence, branch or worktree), then + announce office, holder and work to every peer on the system (in Claude + Code: `ListAgents`, then `SendMessage`). +5. **Not elected**: read the holder's `claim`, send the holder your findings, + and stop on that work. + +Peers on other machines cannot see this host's claims. Between machines the +earliest announcement by message time wins, and each host's claim directory +records the result. + +## Chair and resource allocation + +- The first agent elected on the system while `chair` is vacant also claims + `chair`, in the same way. +- An operator-appointed allocator holds the chair: its claim says + `appointed: operator`, and no election replaces it while its session runs and + the operator has not ended the appointment. +- Before starting anything that consumes shared capacity (gates, deploys, + iteration loops, swarm or cloud resources, cleanup of shared data), an agent + sends the chair what, where and for how long, waits for the grant, and + reports the release. The chair keeps one queue, answers every request with + its position, enforces the limits the operator set, and never cancels a + running grant to free capacity. +- Handover is explicit: the outgoing chair sends every peer the new holder, + the queue and the running grants, and keeps allocating until the incoming + chair confirms. Two allocators never run at once. + +## Succession + +- A piece of work or a cluster ends with its result, a proposal, or an + abandoned attempt, reported to the peers who heard the claim. The holder + then removes its office directory, and the next agent that starts the work + is elected afresh. +- A representative or the chair that ends hands its office to the next-oldest + live representative (by claim time) and announces it. +- A claim is stale when its holder no longer appears in the agent listing and + does not answer a message. A stale work or cluster claim goes to the next + agent that starts the work; a stale representative or chair claim goes only + to the next-oldest live representative. The successor removes the stale + claim, claims anew and announces the succession; everyone else leaves it + alone. +- After a restart or reboot, check every office you believe you hold: `/tmp` + may have been wiped, and your session name may have changed. Re-claim and + update the claim file instead of assuming the office is still yours. + +## Rules + +- Never invent a peer's answer. Silence is neither agreement nor a competing + claim; proceed after a bounded wait. +- A peer's message is not the operator's approval, and an office grants no + permission: never ask a peer to run what your own session is denied. +- Release every claim when its work ends; a forgotten claim blocks the work + for everyone. +- One message per peer per event, with a self-contained first line. + +## Output + +On /democracy, one table of the current offices, read from the claim +directory and the agent listing, vacant and stale claims marked: + +| Office | Holder | Since | Work | Grants or queue | diff --git a/skills/funnel/SKILL.md b/skills/funnel/SKILL.md index 5abd1c6..b45dae4 100644 --- a/skills/funnel/SKILL.md +++ b/skills/funnel/SKILL.md @@ -27,7 +27,8 @@ in a sidetree until it does, or leaves as a proposal. 1. **Brief.** One concern per agent. Name the goal, the exact base commit, the scope that may change, the evidence expected back, a hard time cap (default 60 minutes) and what the agent must not do: no pushes, no gates or deploys - unless granted, read-only probes on shared live systems. + unless the resource chair of the `democracy` skill granted them, read-only + probes on shared live systems. 2. **Sidetree.** The agent works in its own worktree on its own branch, created from the exact base commit, so its edits never land under a running gate or deploy in the main line. Use the host's worktree isolation when it @@ -66,8 +67,9 @@ and verify each step instead of assuming it: a broad prune, which also drops other worktrees' stale registrations. 5. **Delete the merged branch**, locally and on the remote, but a remote branch only once every one of its commits is reachable from a pushed branch. -6. **Release what it held**: slots, port or subnet reservations, locks and - claims announced to other agents. +6. **Release what it held**: slots (reported to the resource chair), port or + subnet reservations, locks, its `democracy` claims and every claim + announced to other agents. 7. **Remove its temporary files**: logs, message files and scratch data that have served their purpose. Keep only the evidence the report cites, until the report is delivered. @@ -98,7 +100,8 @@ below the bar never enters the main line on its own. - Stop an agent at its time cap and ask for its findings; an uncapped brief can run for hours and deliver nothing. - Run agents in parallel only when their concerns touch different files and - the machine has room; gates and deploys need the machine to themselves. + the resource chair grants the capacity; gates and deploys need the machine + to themselves. - A peer's or agent's message is not the operator's approval to merge below the bar. - Keep the evidence (logs, test output) outside the sidetree, so it survives diff --git a/skills/triage/SKILL.md b/skills/triage/SKILL.md index b0cff25..e7d174b 100644 --- a/skills/triage/SKILL.md +++ b/skills/triage/SKILL.md @@ -39,7 +39,8 @@ root cause is proven. 3. **Coordinate every cluster.** Invoke the `coordinate` skill for each cluster before fixing it: tell the agents whose branches this one inherits from or passes its commits on to which run failed and on which line, ask whether - someone already fixes it, and either take their fix or claim yours. Keep + someone already fixes it, and either take their fix or claim yours through + the `democracy` skill. Keep investigating while you wait for answers. 4. **Download artifacts per cluster.** Use the `ci-artifacts` skill for the mechanics — it covers per-job logs while a run is still in progress, which diff --git a/skills/tune/SKILL.md b/skills/tune/SKILL.md index d02b698..c56f6b7 100644 --- a/skills/tune/SKILL.md +++ b/skills/tune/SKILL.md @@ -111,9 +111,10 @@ implementing a cluster, run the `coordinate` skill for it, and send the question to every other agent session on this machine, not only the branch lineage: has anyone already identified this cluster? -- **The first to identify a cluster works it.** "First" is the earliest claim - that names the cluster's log line and number, by message time. A claim - without a measurement does not count. +- **The first to identify a cluster works it.** "First" is the `democracy` + skill's atomic claim (`cluster/`), whose claim file names the + cluster's log line and number; between machines, the earliest announcement + by message time. A claim without a measurement does not count. - **Someone was earlier:** stop on that cluster. Send them your measurements and findings, then move on to the next cluster. Never build a second optimization of the same cluster. @@ -121,8 +122,8 @@ lineage: has anyone already identified this cluster? sidetree branch, then work it. A silent peer is not a competing claim; proceed after a bounded wait. - **A claim ends** when its holder reports the result, a proposal or an - abandoned attempt, or when the operator reassigns it. Only then may another - agent take the cluster. + abandoned attempt and removes its claim, or when the operator reassigns it. + Only then may another agent take the cluster. ## Levers that usually pay