Skip to content

gkotsia/Snowveil

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Snowveil (version Alpha)

A coordination primitive for AI agents to converge on ranked options through gossip-based probabilistic consensus.

What it is

Snowveil implements a protocol based on this paper Snowveil: A Framework for Decentralised Preference Discovery (Kotsialou). Multiple independent agents submit ranked preferences and converge on a global ranking via probabilistic peer sampling — no central coordinator required.

The library serves both in-process use cases (CrewAI, single-host LangGraph) via InMemoryTransport and cross-process / cross-organisational use cases via WebSocketTransport with Ed25519-signed messages.

Installation

pip install snowveil    # not yet on PyPI; v0.1.0 release pending

For development:

pip install -e ".[dev]"

Quickstart

Pick the mode that matches your deployment. All three converge on the same consensus given the same submitted profile.

1. In-process — single-host crews

The default path for CrewAI, single-host LangGraph, tests, and demos. Zero network deps.

from snowveil import Snowveil, Config

sv = Snowveil(candidates=["search", "ask_user", "draft_reply", "escalate"],
              config=Config(seed=0))

sv.submit("researcher", ["search", "ask_user", "draft_reply", "escalate"])
sv.submit("writer",     ["draft_reply", "search", "ask_user", "escalate"])
sv.submit("qa",         ["search", "draft_reply", "ask_user", "escalate"])
sv.submit("manager",    ["search", "ask_user", "draft_reply", "escalate"])

sv.run()
sv.get_consensus()[0]   # → "search"

2. Distributed — two processes / two hosts

Use WebSocketCluster to collapse the Ed25519 + server lifecycle + transport boilerplate into a single async context manager. Each side runs the same code with its own LocalAgent and the peer's verify key:

from snowveil import Config
from snowveil.transport.cluster import WebSocketCluster, RemoteAgent
from snowveil.transport.identity import Identity

async with WebSocketCluster.serve(
    candidates=["A", "B"],
    local_agent=("alice", ["A", "B"]),
    listen="ws://localhost:9001",
    peers=[RemoteAgent("bob", "ws://localhost:9002", bob_verify_key)],
    identity=Identity.generate(),
    config=Config(seed=0),
) as cluster:
    await cluster.run()
    cluster.consensus            # → ["A", "B"]

Runnable two-terminal demo: examples/two_process_websocket.py. For asymmetric setups (multiple voters per node, shared transport across crews) drop down to WebSocketServer + WebSocketTransport directly.

3. CrewAI drop-in — Process.consensual

Status: Process.consensual is currently in an upstream CrewAI PR; until it merges, this snippet requires a CrewAI build that ships the consensual process and consensus= field. Layers 1 (snowveil_consensus) and 2 (crewai_ranker) work on stock upstream CrewAI today.

Once CrewAI's Process.consensual is available, swap the manager LLM for SnowveilConsensus:

from crewai import Crew, Process
from snowveil.integrations.crewai import SnowveilConsensus

crew = Crew(
    agents=[researcher, writer, qa],
    tasks=[task],
    process=Process.consensual,
    consensus=SnowveilConsensus(),
)
crew.kickoff()

For frameworks without a ConsensusEngine hook, the lower-level primitive snowveil_consensus(rankers, options, question) works against any callable that returns LLM text. See examples/integration_crewai.py.

When to choose Snowveil over majority vote

CrewAI's default MajorityVoteConsensus and Snowveil's SnowveilConsensus solve the same problem at different fidelities. Use majority vote when speed matters and the decision is uncontested; reach for Snowveil when any of the following hold:

  • Plurality picks a divisive winner. Concrete example: 5 voters, 3 options, profile [A>C>B, A>C>B, B>C>A, B>C>A, C>A>B]. Plurality first-place votes are A=2, B=2, C=1, so plurality picks A or B (a coin flip). But everyone ranks C ≥ 2nd, and Borda totals are A=5, B=4, C=6. Snowveil's CHB rule picks C — the candidate the whole electorate finds acceptable, not the one with the slim divisive plurality.
  • Coalition resistance is needed. Snowveil's Ω(n) coalition lower bound (paper §4.6, validated empirically by tests/test_t9_coalition_resistance.py) means a √n-sized coordinated group cannot reliably flip the outcome. Majority vote flips the moment a coalition crosses 50 %.
  • The full ranking matters, not just the top pick. Majority vote returns one winner; sv.get_consensus() returns the full social ranking [w_1, w_2, ..., w_m] via sequential elimination, useful for top-k routing, fallback chains, or auditable tie-breaking.
  • Inputs are noisy or partially informed. Probabilistic peer sampling smooths individual-voter mistakes — voters update toward the local consensus before locking. With high-variance LLM voters, this routinely produces more stable winners across re-runs than majority vote.
  • Decisions cross organisational trust boundaries. Snowveil's WebSocketTransport ships with Ed25519 signing and replay protection. Two crews from different organisations can converge without either acting as a central tally authority.

If your decision is unanimous or near-unanimous and runs entirely inside one process, majority vote is faster and simpler — use it. The cost difference is one extra sv.run() (milliseconds at typical crew sizes), so if any of the above apply, the upgrade is cheap.

Recommended parameters

The defaults in Config() reproduce the paper baseline used in the paper's reference notebooks. Use them unchanged for the well-validated regime; deviate only with awareness of the trade-offs described in the notebook.

Parameter Default Meaning When to change
k 10 Peer sample size per round Lower for very small electorates (k ≤ n − 1 is required); higher for adversarial robustness
gamma 10 Max rounds in the Voter Update Process Higher for more conservative locking; lower for faster convergence
tau_max 6 Early-lock threshold (out of gamma) Roughly floor(gamma/2) + 1
tau_min 3 Minimum-support threshold Roughly ceil(gamma/4)
quorum 0.67 Global termination threshold Q ∈ (0.5, 1] Higher for stricter consensus; closer to 0.5 weakens uniqueness
alpha 0.1 CHB popularity filter (plurality threshold) Higher to reject narrow-plurality winners
beta 0.8 CHB consensus filter (Borda threshold) Lower to admit more eligible candidates
lambda_ 0.5 CHB hybrid weight (consensus vs plurality) 0.0 = pure consensus; 1.0 = pure plurality
seed None RNG seed for reproducibility Set for deterministic runs / parity tests

Electorate sizing. The protocol's statistical guarantees were validated for n ≥ 100 voters in the paper. The baseline k=10 requires at least 11 voters. For tiny crews (CrewAI with 3–8 agents), set k to n − 1 and accept that the convergence guarantees weaken — the protocol is not designed for n < 20.

Marginal-parameter behaviour. At k = 5 or γ = 5 (well below baseline), the library's per-voter model exposes individual-voter variance that the paper's mass-action notebook simulator smooths over — so you may see 90–98% accuracy. This is correct behaviour, not a bug.

Known limitations

  • v1 ships only WebSocket as a network transport. gRPC, libp2p, MQTT are out of scope and can be added against the same Transport protocol later.
  • Static peer list only — no dynamic peer discovery, PKI, or sybil resistance. Sufficient for federated and cross-org cases where participants are known a priori.
  • Each run() starts from a clean state vector; no durable resume.
  • Multi-stage distributed mode (m > 2 candidates with the engine distributing across processes for every stage) works in tests but needs more validation on real networks. Single-stage demos are the recommended path for v0.1.0.

Documentation

Citation

Paper: https://arxiv.org/abs/2512.18444.

License

MIT — see LICENSE.

About

Decentralised preference discovery and decision-making for autonomous AI systems

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages