Metadata-Version: 2.4
Name: snowveil
Version: 0.1.0
Summary: Coordination primitive for AI agents to converge on ranked decisions through gossip-based probabilistic consensus.
Project-URL: Homepage, https://github.com/gkotsia/Snowveil
Project-URL: Repository, https://github.com/gkotsia/Snowveil
Project-URL: Issues, https://github.com/gkotsia/Snowveil/issues
Project-URL: Paper, https://arxiv.org/abs/2512.18444
Author: Grammateia Kotsialou
License-Expression: MIT
License-File: LICENSE
Keywords: agents,consensus,gossip,multi-agent,preference-aggregation,snowveil,social-choice
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: System :: Distributed Computing
Requires-Python: >=3.11
Requires-Dist: numpy>=1.26
Requires-Dist: pynacl>=1.5
Requires-Dist: scipy>=1.11
Requires-Dist: websockets>=12.0
Provides-Extra: crewai
Requires-Dist: crewai>=0.80; extra == 'crewai'
Provides-Extra: dev
Requires-Dist: hypothesis>=6.0; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# 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*](https://arxiv.org/abs/2512.18444) (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

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

For development:

```bash
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.

```python
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:

```python
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`](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`:

```python
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`](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](https://arxiv.org/abs/2512.18444)'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

- [Project brief](docs/project-brief.md) — what Snowveil is and why
- [Architecture](docs/architecture.md) — modules, data model, execution flow, transport design

## Citation

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

## License

MIT — see [LICENSE](LICENSE).
