Run agents without a leader.
kslate gives your agents a trusted, audited shared record.
For two or more agents working the same task at the same time.
$ git clone https://github.com/kslate-dev/kslate
$ cd kslate
$ make runTrusted
Every write is checked against what the agent read:
- the field versions
- what it was based on
- its lease
- its role
- an identity kslate verified, not one the agent claims
# a write whose premise moved
$ python remediator.py
rejected: planned_action moved v1 -> v2 by apikey:diagnoserAudited
Every write and every rejection is kept, with its author, its evidence and what it was based on. kslate blame reads it back.
$ kslate blame --server http://127.0.0.1:8080 incidents/inc-1 actions_taken
actions_taken (append, evidence required)
v1 23:04:44 apikey:remediator "executed: roll back api deployment"
evidence: kubectl output
based_on: planned_action@2
identity: apikey:remediator (shared-secret)
-- 23:04:20 apikey:remediator REJECTED STALE_PREMISE
based_on: planned_action@1How it works
Each agent runs its own loop: read the record, claim work, act, write back. Like Kubernetes controllers coordinating through the API server, agents never message each other or wait on a supervisor. kslate makes the shared record safe to coordinate through.
- 01read the record
- 02claim work
- 03act
- 04write back
Four agents, one record
Four agents handle one incident through one record. No agent calls another. The struck-through edge is a write kslate rejected because the plan it was based on had moved; the write below it, based on the current plan, was accepted. What is kslate? walks through this exchange.
flowchart LR
detector([detector])
diagnoser([diagnoser])
remediator([remediator])
communicator([communicator])
subgraph rec["record incidents/inc-4471"]
direction TB
symptoms["symptoms · append · entries 1–3"]
hypotheses["hypotheses · append · entries 1–6"]
planned_action["planned_action · versioned · v5"]
actions_taken["actions_taken · append"]
customer_updates["customer_updates · append"]
end
detector -->|"append · entries 2, 3"| symptoms
diagnoser -->|"append · based_on symptoms@3"| hypotheses
diagnoser -->|"put · v4 → v5 · evidence hypotheses@6"| planned_action
remediator rejected@-->|"<s>append · based_on planned_action@4</s><br>REJECTED STALE_PREMISE · planned_action moved 4 → 5 by diagnoser"| actions_taken
remediator -->|"append · based_on planned_action@5 · accepted"| actions_taken
communicator -->|"append · when actions_taken moves"| customer_updates
The rejected write stays in the record's history with who sent it and what had changed. kslate blame shows it. kslate does not merge writes, does not retry for the agent, and does not decide which agent was right.