converge-core

Crates.ioconverge-core
lib.rsconverge-core
version1.0.0
created_at2026-01-07 14:23:17.498252+00
updated_at2026-01-24 18:42:00.863633+00
descriptionConverge Agent OS - correctness-first, context-driven multi-agent runtime
homepage
repository
max_upload_size
id2028321
size1,350,079
Kenneth Pernyer (kpernyer)

documentation

https://docs.rs/converge-core

README

Converge Core

Context is the only shared state. The engine decides; agents propose.

A correctness-first, context-driven multi-agent runtime library.

Crates.io Documentation

Website: converge.zone | Docs: docs.rs | Crates.io: converge-core


What Is Converge Core?

Converge Core is the foundational semantic engine of the Converge ecosystem. It provides:

  • Context — The single source of truth, append-only and typed
  • Engine — The convergence loop that orchestrates agents to a fixed point
  • Agent Trait — The contract for capabilities that observe and propose
  • Invariants — Runtime constraints that guard correctness (Gherkin-style)
  • Capability Traits — Interfaces that providers implement

What Converge Core IS

Aspect Description
The authority The engine decides what becomes a Fact
Context owner Context is the API; all collaboration happens through it
Convergence guarantor Execution proceeds until a fixed point is reached
Invariant enforcer Constraints are checked continuously and at convergence
Trait definer Defines Agent, LlmProvider, Embedding, etc.

What Converge Core is NOT

Anti-pattern Why Not
Not a workflow engine No predefined steps; agents react to context
Not an event bus No pub/sub; context changes trigger eligibility
Not an actor system Agents never call each other; no message passing
Not eventual consistency Convergence is explicit and observable
Not provider implementations Providers live in converge-provider

Core Axioms

These are the non-negotiable principles that define Converge.

1. Context Is the Only Shared State

Agents do not call each other. They read Context and emit effects. Context is the API.

2. Agents Propose, Engine Decides

Agents return AgentEffect containing Fact or ProposedFact. The engine validates, merges, and commits.

3. Convergence Is Mandatory

Execution proceeds until:

  • Context_{n+1} == Context_n (fixed point), or
  • Budget exhausted, or
  • Invariant failed

4. Correctness Over Availability

Wrong answers are worse than no answers. Invariants block invalid states.

5. Determinism Is Transparent

Same input → same output. All decisions are traceable.

6. LLMs Suggest, Never Decide

LLM outputs become ProposedFact, not Fact. Validators promote proposals after verification.


Converging Flow Principles

Beyond the core axioms, Converge is built on a systems-level understanding of converging flows.

What Is a Converging Flow?

A converging flow is a goal-directed, multi-agent process where:

  • Multiple partial perspectives iteratively reduce uncertainty
  • Progress is measured by reduction of ambiguity, not by speed or steps completed
  • Execution continues until a stable decision, artifact, or state is reached

Canonical Phases

All flows decompose into six structural phases:

Intent → Framing → Exploration → Tension → Convergence → Commitment

If any phase is missing, the system oscillates, over-optimizes locally, or produces brittle outcomes.

Flow Truths

Intent must be explicit. Without declared intent, convergence must not begin.

Constraints precede exploration. Exploration without surfaced constraints produces invalid outcomes.

Tension is mandatory. If multiple perspectives immediately agree without conflict, force contradiction search.

Commitment freezes state. The system must commit or explicitly defer — no ambiguous endings.

Flow Classification

Flows are classified by dominant uncertainty:

  • Epistemic ("What is true?") — high exploration, late commitment
  • Pragmatic ("What works?") — bounded exploration, early feasibility pruning
  • Normative ("What should be done?") — explicit values, narrative convergence
  • Strategic ("What matters most?") — reframing loops, ranking under uncertainty

See converge-business/knowledgebase/core-CONVERGING_FLOWS.md for the complete flow theory.


Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        converge-core                            │
│  The foundational layer. Depends on NOTHING in the ecosystem.   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐         │
│  │   Engine    │    │   Context   │    │  Invariant  │         │
│  │  (decides)  │───▶│  (shared)   │◀───│  (guards)   │         │
│  └─────────────┘    └─────────────┘    └─────────────┘         │
│         │                  ▲                                    │
│         │                  │                                    │
│         ▼                  │                                    │
│  ┌─────────────┐    ┌─────────────┐                            │
│  │   Agent     │───▶│ AgentEffect │                            │
│  │ (proposes)  │    │  (buffered) │                            │
│  └─────────────┘    └─────────────┘                            │
│                                                                 │
│  Trait Definitions:                                             │
│  • Agent           • LlmProvider      • Embedding               │
│  • Invariant       • VectorRecall     • GraphRecall             │
│  • Reranking       • ModelSelector                              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
                              │
                              │ implements traits
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                     converge-provider                           │
│  Capability adapters (Anthropic, OpenAI, Gemini, etc.)          │
└─────────────────────────────────────────────────────────────────┘
                              │
                              │ uses providers in agents
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      converge-domain                            │
│  Domain agents, use cases, business logic                       │
└─────────────────────────────────────────────────────────────────┘

Dependency Rules

Crate May Depend On Must NOT Depend On
converge-core (nothing) converge-provider, converge-domain
converge-provider converge-core converge-domain
converge-domain converge-core, converge-provider

Installation

[dependencies]
converge-core = "0.6"

Related Crates

Crate Version Description
converge-core 0.6.2 Runtime engine, agent traits, capabilities
converge-provider 0.2.4 14+ LLM providers, model selection
converge-domain 0.2.4 12 business use cases

Quick Start

use converge_core::{Engine, Context, ContextKey, Fact, Agent, AgentEffect};

// Define a simple agent
struct GreetingAgent;

impl Agent for GreetingAgent {
    fn name(&self) -> &str { "greeting" }
    fn dependencies(&self) -> &[ContextKey] { &[ContextKey::Seeds, ContextKey::Signals] }

    fn accepts(&self, ctx: &Context) -> bool {
        ctx.has(ContextKey::Seeds) &&
        !ctx.get(ContextKey::Signals).iter().any(|f| f.id.starts_with("greeting-"))
    }

    fn execute(&self, _ctx: &Context) -> AgentEffect {
        AgentEffect::with_fact(Fact::new(
            ContextKey::Signals,
            "greeting-response",
            "Hello from Converge!",
        ))
    }
}

fn main() {
    let mut engine = Engine::new();
    engine.register(GreetingAgent);

    let mut ctx = Context::new();
    ctx.add_fact(Fact::new(ContextKey::Seeds, "input", "Start")).unwrap();

    let result = engine.run(ctx).expect("should converge");
    println!("Converged in {} cycles", result.cycles);
}

Core Types

Context

The shared, typed, evolving state of a job.

pub struct Context {
    // Internally organized by ContextKey
    // Seeds → Signals → Hypotheses → Strategies → Evaluations
}

pub enum ContextKey {
    Seeds,       // Initial input data
    Signals,     // Observations and discoveries
    Hypotheses,  // Tentative conclusions
    Strategies,  // Proposed solutions
    Evaluations, // Quality assessments
    Constraints, // Domain constraints
    Proposals,   // Pending LLM suggestions
    Approvals,   // Human-approved items
}

Agent

A capability that reads context and emits effects.

pub trait Agent: Send + Sync {
    /// Unique name for this agent
    fn name(&self) -> &str;

    /// Context keys this agent depends on
    fn dependencies(&self) -> &[ContextKey];

    /// Whether this agent should run given current context
    fn accepts(&self, ctx: &Context) -> bool;

    /// Execute and return effects (facts to add)
    fn execute(&self, ctx: &Context) -> AgentEffect;
}

AgentEffect

Buffered output from an agent. Never mutates context directly.

pub struct AgentEffect {
    pub facts: Vec<Fact>,
    pub proposed_facts: Vec<ProposedFact>,
    pub trace: Option<String>,
}

Fact vs ProposedFact

┌─────────────────────────────────────────────────────────────────┐
│                        TRUST LEVELS                             │
├─────────────────────────────────────────────────────────────────┤
│  Fact (authoritative)        │  ProposedFact (tentative)       │
│  ─────────────────────────   │  ─────────────────────────────  │
│  Emitted by deterministic    │  Emitted by LLM agents          │
│  agents or promoted from     │  Requires validation before     │
│  validated proposals         │  becoming a Fact                │
│  Added directly to Context   │  Held in Proposals key          │
└─────────────────────────────────────────────────────────────────┘

Engine

The convergence loop that orchestrates agents.

pub struct Engine {
    agents: Vec<Box<dyn Agent>>,
    invariants: Vec<Box<dyn Invariant>>,
    budget: Budget,
}

impl Engine {
    /// Run until convergence or budget exhaustion
    pub fn run(&self, ctx: Context) -> Result<ConvergeResult, ConvergeError>;
}

Agent Idempotency Contract

All agents must follow this rule:

An agent has contributed if any artifact it emitted exists in the context — regardless of acceptance or validation.

impl Agent for MyAgent {
    fn dependencies(&self) -> &[ContextKey] {
        // Include BOTH input AND output keys
        &[ContextKey::Seeds, ContextKey::Hypotheses]
    }

    fn accepts(&self, ctx: &Context) -> bool {
        // 1. Check precondition
        if !ctx.has(ContextKey::Seeds) { return false; }

        // 2. Check idempotency (context-based, not hidden state)
        let my_prefix = format!("{}-", self.name());
        !ctx.get(ContextKey::Hypotheses)
            .iter()
            .any(|f| f.id.starts_with(&my_prefix))
    }

    fn execute(&self, _ctx: &Context) -> AgentEffect {
        AgentEffect::with_fact(Fact::new(
            ContextKey::Hypotheses,
            "myagent-result-1",
            "derived content",
        ))
    }
}

Invariants

Runtime constraints that guard correctness.

pub trait Invariant: Send + Sync {
    /// Name of this invariant
    fn name(&self) -> &str;

    /// When to check: Structural, Semantic, or Acceptance
    fn class(&self) -> InvariantClass;

    /// Check the invariant against current context
    fn check(&self, ctx: &Context) -> InvariantResult;
}

pub enum InvariantClass {
    /// Checked on every merge (schema, types)
    Structural,
    /// Checked per-cycle (domain rules)
    Semantic,
    /// Checked at convergence (success criteria)
    Acceptance,
}

Capability Traits

Traits for providers to implement.

// LLM completion
pub trait LlmProvider: Send + Sync {
    fn name(&self) -> &str;
    fn model(&self) -> &str;
    fn complete(&self, request: &LlmRequest) -> Result<LlmResponse, LlmError>;
}

// Embeddings
pub trait Embedding: Send + Sync {
    fn embed(&self, request: &EmbedRequest) -> Result<EmbedResponse, CapabilityError>;
}

// Vector similarity search
pub trait VectorRecall: Send + Sync {
    fn query(&self, query: &VectorQuery) -> Result<Vec<VectorMatch>, CapabilityError>;
}

// Graph pattern matching
pub trait GraphRecall: Send + Sync {
    fn query(&self, query: &GraphQuery) -> Result<GraphResult, CapabilityError>;
}

// Re-ranking
pub trait Reranking: Send + Sync {
    fn rerank(&self, request: &RerankRequest) -> Result<RerankResponse, CapabilityError>;
}

Guarantees

Guarantee Mechanism
Determinism Agents sorted by name; effects merged in order
Termination Budget limits cycles, facts, and wall-clock time
Isolation Agents read-only context; effects buffered
Auditability Every fact has provenance
Correctness Invariants block invalid states

Execution Model

repeat
    1. Determine eligible agents (accepts() == true)
    2. Execute eligible agents in parallel (read-only context)
    3. Collect AgentEffects (buffered)
    4. Merge effects into context (serialized, deterministic order)
    5. Check structural invariants (immediate)
    6. Check semantic invariants (per-cycle)
until
    Context unchanged (convergence) OR
    Budget exhausted OR
    Invariant failed

finally
    Check acceptance invariants (convergence gate)

Testing

# Run all convergence axiom tests
cargo test -p converge-core --test engine_convergence_axioms -- --nocapture

# Run all tests
cargo test -p converge-core

# Run property-based tests
cargo test -p converge-core --test property_tests

Test Categories

Test File What It Tests
engine_convergence_axioms Core convergence guarantees
convergence Basic convergence behavior
parallel_execution Parallel agent execution
transparent_determinism Determinism guarantees
hitl_pause_resume_axioms Human-in-the-loop flows
property_tests Property-based testing

Documentation

See docs/ for detailed documentation:


Repository

This crate is part of the Converge project.

Standalone repo: github.com/kpernyer/converge-core

License

Proprietary (Aprio One AB)

Commit count: 0

cargo fmt