quorum-rs 0.7.0-rc.6

Rust SDK and CLI for multi-agent deliberation systems — ships the `quorum` binary (run / status / trace / tui / init) plus the underlying agent, LLM, tool, prompt, and worker library.
docs.rs failed to build quorum-rs-0.7.0-rc.6
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: quorum-rs-0.7.0-rc.4

quorum-rs

Crates.io Docs.rs License

Rust SDK and CLI for multi-agent deliberation systems — agents that propose, evaluate, and reach quorum on outcomes over a NATS-based orchestration protocol. Library and binary ship in the same crate.

Install

As a library:

[dependencies]
quorum-rs = "0.6"

As the quorum CLI (run, status, trace, tui, init):

cargo install quorum-rs

Default features build the binary (cli + tui). To use as a pure library and skip the CLI deps (clap, ratatui, etc.):

[dependencies]
quorum-rs = { version = "0.6", default-features = false, features = ["audit"] }

MSRV: Rust 1.85 (uses Edition 2024).

CLI quick reference

quorum init                Bootstrap an `nsed.yaml` workspace config
quorum redeem <code>       Redeem a JWT invite — writes ~/.nsed/operator.token
                           and (for unified codes) ~/.nsed/agent.creds + .seed
quorum serve               Run an agent fleet from agent.yml. Reads creds
                           from ~/.nsed/agent.creds (default)
quorum run <task>          Submit a deliberation task to the orchestrator
quorum status              Health check + agent status
quorum trace <job_id>      Show a deliberation trace (verdict + evaluations)
quorum tui                 Interactive terminal UI (live deliberation view)

run, status, trace, tui read ./nsed.yaml by default (--config <path> to override). serve reads ./agent.yml by default.

What's inside

Module Key types Purpose
agents NsedAgent, AgentContext, Proposal, Evaluation, ChatCapable, OutputLeakDetector Agent trait + deliberation data structures + pluggable output guard
agents::config AgentConfig, TaskPrecision Agent configuration (model, provider, limits)
providers ProviderFactory, ProviderRegistry, cli_base Dispatch registry mapping provider.type → agent factory (register custom providers without forking); cli_base shares exec/mcp subprocess spawn + timeout helpers
llms AiModel, RequestConfig, SimpleOpenAIModel, OpenAICompatibleModel, RateLimiter LLM abstraction + production streaming client + simulator / stub for tests
prompts PromptSet, DefaultPromptSet Prompt template interface + benchmark-validated default proposer/evaluator templates
tools Tool, ToolDefinition, ScopedGrepTool, ScopedReadFileTool Tool-use interface (OpenAI function calling) + sandboxed filesystem tools
workers NatsNsedWorker, WorkerConfig, NatsScratchpadStore, WorkerHook, UserToolHandlerFactory NATS JetStream worker runtime
middleware AgentMiddleware, MiddlewarePipeline, MiddlewareConfig, RuleBasedMiddleware, LlmModerationMiddleware, BinaryMiddleware, DylibMiddleware Pluggable validation/moderation + YAML config + external-process dispatch
status AgentStatusSnapshot, SharedAgentStatus, server, multi_server Real-time status types + optional HTTP dashboard (feature status-server)
nats_utils connect_nats, sanitize_subject_component, NatsAuth NATS helpers + authentication
telemetry TelemetryEvent, TelemetryConfig, TelemetryEmitter Per-agent telemetry event catalog

Quick start — build a custom agent

use quorum_rs::agents::{NsedAgent, AgentContext, AgentConfig, Proposal, Evaluation, Stance};
use quorum_rs::llms::SimpleOpenAIModel;
use quorum_rs::workers::{NatsNsedWorker, WorkerConfig};
use async_trait::async_trait;
use anyhow::Result;

struct MyAgent {
    name: String,
    llm: SimpleOpenAIModel,
}

#[async_trait]
impl NsedAgent for MyAgent {
    fn name(&self) -> &str {
        &self.name
    }

    async fn propose(&self, context: &AgentContext) -> Result<Proposal> {
        // your proposal logic — call self.llm, return a Proposal
        unimplemented!()
    }

    async fn evaluate(
        &self,
        context: &AgentContext,
        proposals: &[Proposal],
    ) -> Result<Vec<Evaluation>> {
        // your evaluation logic — return Vec<Evaluation> with stance + scores
        unimplemented!()
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    let agent = MyAgent {
        name: "my-agent".into(),
        llm: SimpleOpenAIModel::new(
            "https://api.openai.com/v1".into(),
            std::env::var("OPENAI_API_KEY")?,
            "gpt-4o-mini".into(),
        ),
    };

    let config = WorkerConfig::new(
        "nats://localhost:4222".into(),
        "sphera_jobs".into(),
        "my_agent_consumer".into(),
    );

    let worker = NatsNsedWorker::new(agent, AgentConfig::default(), config, None).await?;
    worker.run().await
}

Use the reference agent

If you want the full ReAct loop, structured proposer/evaluator outputs, retry + repair, tool injection, and benchmark-validated prompts, use ProposerEvaluatorAgent instead of implementing NsedAgent from scratch:

use quorum_rs::agents::{AgentConfig, ProposerEvaluatorAgent};
use quorum_rs::llms::OpenAICompatibleModel;
use quorum_rs::prompts::defaults::DefaultPromptSet;
use quorum_rs::workers::{NatsNsedWorker, NatsNsedWorkerExt, WorkerConfig};

# async fn run() -> anyhow::Result<()> {
let agent_config = AgentConfig {
    name: "cortex-a".into(),
    provider_id: "openai".into(),
    model_name: "gpt-4o".into(),
    ..Default::default()
};

let agent = ProposerEvaluatorAgent::new(
    agent_config,
    Box::new(OpenAICompatibleModel::new(
        "https://api.openai.com/v1".into(),
        std::env::var("OPENAI_API_KEY")?,
        None,
    )),
    Box::new(DefaultPromptSet::new()),
    vec![],
    vec![],
);

let worker_config = WorkerConfig::new(
    "nats://localhost:4222".into(),
    "sphera_jobs".into(),
    "cortex_a_consumer".into(),
);
let worker = NatsNsedWorker::from_agent(agent, worker_config).await?;
worker.run().await
# }

Pre-built agent shells

For agents you don't write in Rust:

Type Use when
ExecAgent The agent is a process you exec (any language); deliberation I/O via stdin/stdout JSON
McpAgent / ClaudeAgent The agent is an MCP server (Claude Code, generic MCP) wrapped via the SDK runtime

Features

  • default = ["audit"]
  • audit — enables cryptographic signing of agent outputs via quorum-crypto-core
  • status-server — embedded axum dashboard for live agent + fleet status (HTTP)

Sister crates

Part of the quorum-rs workspace:

  • llm-repair — JSON-repair / markdown-extraction / tool-call recovery for malformed LLM output
  • quorum-crypto-core — ed25519 / secp256k1 / SHA3 + audit envelope (used by the audit feature)

License

Dual-licensed under either:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.