The complete Raft consensus algorithm — leader election, log replication, safety, persistence, snapshots, and cluster membership changes — implemented twice, in Go and in Rust, as mirror images of each other, plus a visual debugger that shows you which source line each node is executing while a real cluster runs.
This repository is built for reading. Roughly 40% of the source is explanation: every file opens with an essay on why it exists, and the tricky lines cite the section of the Raft paper they implement.
Start here → GUIDE.md — the concepts, then a guided tour of the code in reading order, then Go-vs-Rust notes.
Requirements: Go ≥ 1.22, Rust ≥ 1.75 (Linux/macOS).
$ scripts/build.sh # builds Go, Rust, and the visualizer
$ scripts/test-all.sh # unit tests + all 12 end-to-end scenarios$ scripts/run-go.sh # or scripts/run-rust.sh
raft> status
id role term commit applied log snapshot leader
n1 follower 1 2 2 [1,2] @0 n3
n2 follower 1 2 2 [1,2] @0 n3
n3 LEADER 1 2 2 [1,2] @0 n3
raft> submit x=5
committed x=5 in 18ms
raft> kill n3 # SIGKILL the leader...
raft> status # ...and watch the re-election
raft> partition n1 | n2,n3 # simulate a network partition
raft> heal
raft> add-server n4 # grow the cluster live
raft> help # everything elseEach node is a real OS process speaking newline-delimited JSON over TCP
(docs/protocol.md). You can talk to one directly:
$ echo '{"type":"GetStatus","from":"me","body":{}}' | nc 127.0.0.1 21001
{"ok":true,"body":{"id":"n1","term":3,"role":"leader",...}}$ scripts/run-visual.sh # go cluster + visualizer; add `rust` for Rust
# open http://127.0.0.1:8080Every node streams trace events — each carrying the source file and line that emitted it plus a full state snapshot. The browser UI gives you:
- the cluster diagram (roles, terms, partitions, RPC arrows) reconstructed as of any event you select — step backward and forward like a debugger;
- each node's replicated log, entry by entry, with commit/snapshot markers;
- a code panel showing the real Go/Rust source with the executing line highlighted;
- buttons that drive the live cluster: put/get, partition/heal, crash a node, force a snapshot.
$ go/bin/raftctl scenario stale-leader # THE safety demo
$ go/bin/raftctl scenario all # the whole tour (6 scenarios)
$ rust/target/release/ctl scenario all # same six, Rust clusterSee docs/scenarios.md for what each one proves.
GUIDE.md ← the book: concepts + code walkthrough (start here)
docs/protocol.md the wire protocol both implementations speak
docs/scenarios.md the six failure stories, explained
go/ Go implementation (stdlib only)
raft/ the algorithm, one concern per file
cmd/raft-node one Raft server = one process
cmd/raftctl orchestrator: REPL + scenarios
orchestrator/ process management, REPL, scenario scripts
rust/ Rust implementation (serde + rand only, no async)
src/ mirrors go/raft file-for-file
src/bin/ node + ctl binaries
visualise/ the visual debugger (server + web UI)
scripts/ build / run / test / clean
Implemented: the full paper — §5 elections & replication & safety, §7 snapshots (single-message InstallSnapshot), and single-server membership changes from the dissertation (chapter 4) with both safety guards. Exactly-once client semantics and linearizable reads (through the log).
Deliberately simplified, each discussed in GUIDE.md where it matters: connection-per-RPC instead of multiplexing; whole-file persistence instead of a WAL; reads through the log instead of ReadIndex/leases; no PreVote; no joint consensus; no snapshot chunking. None of these change the algorithm — they are the production-engineering layer above it.