Core concepts¶
Converge models a distributed operating system for agents. The main abstractions are: agent, identity, message, topic, task, pool, store, and decisions. The runtime executes an agent’s decisions via an executor; discovery, coordination, and policy plug into this model.
Agent¶
An agent is an autonomous computational entity with:
Identity: cryptographic, verifiable (see Identity).
State: e.g. idle, busy, offline; the library does not impose a fixed state machine.
Capabilities: skills and constraints it declares for discovery.
Execution loop: the runtime polls messages and tasks, calls
decide(messages, tasks), and executes the returned decisions.
Agents may be rule-based, LLM-driven (see Extensions), or hybrid. The core Agent class is minimal; subclasses override decide() and optionally lifecycle hooks (on_start, on_stop, on_tick).
Identity¶
Identity is the root of trust:
Immutable, cryptographically verifiable (Ed25519 in the reference implementation).
No usernames or human login semantics.
Used to sign outbound messages and verify authorship.
Exposes a fingerprint (derived from the public key) as the stable agent id.
Identity.generate() creates a full keypair; Identity.from_public_key(public_key) creates a verify-only identity (no private key). The identity registry (converge.network.identity_registry.IdentityRegistry) maps fingerprints to public keys so transports can verify message signatures (e.g. receive_verified() on compatible transports).
Message¶
Messages are the primary communication primitive:
Signed by the sender identity (optional but recommended).
Carry: sender, optional recipient, topics, payload, timestamp, optional task reference.
Serialization:
to_bytes()/from_bytes()(msgpack); payload can be encrypted withencrypt_payload(key)/decrypt_payload(key)(requires 32-byte key; see crypto extension).
Messages support direct (recipient), broadcast (no recipient/topics), or topic-scoped delivery depending on the transport.
Topic¶
A topic is a semantic namespace used for:
Routing messages (e.g. transport topic subscriptions).
Pool formation and scope.
Discovery (agents advertise topics and capabilities).
Topics are structured (namespace + attributes + optional version), not free-text. They serialize via to_dict() / from_dict().
Task¶
A task is a unit of work with:
Id, objective, inputs, optional outputs.
State: PENDING → ASSIGNED → COMPLETED (and FAILED, CANCELLED). Optional evaluator.
Optional assignment, result, and claimed_at (for claim TTL).
Routing (optional):
pool_id,topic, andrequired_capabilitiesrestrict which agents see the task. When the runtime has a pool manager, it callslist_pending_tasks_for_agentso each agent only sees tasks for its pools and capabilities.Constraints (optional): conventional keys include
timeout_sec,deadline,claim_ttl_sec(seconds after claim before the task can be released back to PENDING),max_retries,cpu,memory_mb. Enforcement is by custom executor or safety logic, not the core.
Tasks are first-class: submitted to a task manager, claimed by agents, and reported via decisions. The task manager supports cancel_task and fail_task; call release_expired_claims(time.monotonic()) periodically to release tasks whose claim TTL has elapsed. You can set claim_ttl_interval_sec on AgentRuntime so the runtime periodically calls release_expired_claims automatically (no external cron needed). The task manager can use a store for persistence (e.g. in-memory or file-backed).
Reliability and idempotency¶
Task submission and report are idempotent only if the caller uses stable task IDs or idempotency keys. For safe retries: use client-generated task IDs for submit, or store an idempotency key in task.inputs and deduplicate in your handler.
Message delivery is best-effort by default. Use application-level acks and idempotent handlers where needed. The runtime uses a configurable receive timeout so the listen loop can react to shutdown; Inbox supports maxsize and drop_when_full for backpressure. See Design.
Tools and actions¶
Agents can perform tool invocations by emitting an InvokeTool decision (tool_name, params). The runtime’s StandardExecutor uses an optional ToolRegistry (see converge.core.tools): when an InvokeTool is executed, the executor looks up the tool by name and runs tool.run(params). Implement the Tool protocol (property name, method run(params) -> Any) and register tools on a ToolRegistry; pass the registry to AgentRuntime as tool_registry so the executor can run them. Results are not automatically sent back; the agent can emit ReportTask or SendMessage to report outcomes.
Pool¶
A pool is a scoped sub-network defined by:
Topic(s) and optional task types.
Admission policy (who can join: open, whitelist, token, or custom).
Governance model (e.g. democratic, dictatorial) for dispute resolution.
Set of member agents.
Pools are coordination surfaces. The pool manager creates pools, joins/leaves agents, and persists pools via a store when provided.
Store¶
The store abstraction (converge.core.store.Store) provides key-value persistence: put, get, delete, list(prefix). Implementations include MemoryStore and FileStore (see Extensions). Pool manager, task manager, and discovery service can use a store for durability.
Decisions¶
The agent’s decide(messages, tasks) returns a list of decisions. The runtime executes them via the executor (or a fallback when no pool/task managers are configured). Decision types:
Type |
Purpose |
|---|---|
|
Send a single message (uses network when executor has one). |
|
Join a pool (via pool manager). |
|
Leave a pool. |
|
Create a pool from a spec (id, topics, optional admission_policy). |
|
Submit a task (via task manager). |
|
Claim a pending task. |
|
Report task result and mark completed. |
|
Coordination: bidding, voting, negotiation, delegation (executor uses optional protocols). |
See converge.core.decisions in the API reference.
Trust¶
Trust is non-binary and contextual. The trust model (converge.policy.trust) maintains per-agent scores, updatable from outcomes; discovery queries can use a trust threshold. Trust is computed from history where applicable, not only declared.
Message verification and identity bootstrapping¶
When an IdentityRegistry is passed to AgentRuntime, the runtime uses receive_verified() and only pushes messages that verify against the sender’s public key; unverified messages are dropped (log at debug). Populate the registry from discovery: include public_key in AgentDescriptor when registering (e.g. via build_descriptor, which adds the agent’s identity public key), then after querying, call identity_registry.register(d.id, d.public_key) for each descriptor so received messages can be verified.
Discovery and registration¶
The discovery service holds agent descriptors (id, topics, capabilities, optional public_key). It can load/save descriptors from a store and answers queries (by topics and/or capabilities) over a candidate list. You can pass an optional trust_model to DiscoveryService; when set and query.trust_threshold > 0, results are filtered so only agents with trust score at least the threshold are returned. For store-backed discovery in multi-process deployments: use a shared store and call query(query, refresh_from_store=True) to use the latest descriptors from the store (or query(query) to use the in-memory snapshot loaded at init). Agents register on runtime start and unregister on stop: when you pass discovery_service (and optionally agent_descriptor) to AgentRuntime, the runtime registers the agent at start so peers can find it by topic/capability, and unregisters it at stop. Use build_descriptor(agent) from converge.network.network to build a descriptor from an agent’s id, topics, and capabilities when you do not provide one. The network (AgentNetwork) wraps a transport and local agent set and exposes discover(query) using descriptors registered with it.
Governance and safety¶
Pools enforce local rules (admission, governance model, optional trust threshold). When a pool has trust_model and trust_threshold, join is allowed only if the agent’s trust score is at least the threshold.
Policy enforcement in the executor: When StandardExecutor is given a safety_policy (ResourceLimits, ActionPolicy), it checks ActionPolicy before each decision (only allowed types run) and validates task resource constraints (cpu, memory_mb) for SubmitTask/ClaimTask.
Policy modules provide admission (open, whitelist, token), trust, governance (e.g. democratic, dictatorial, bicameral, veto, empirical), and safety (resource limits, action allowlists). You can implement a custom governance model by subclassing GovernanceModel and implementing resolve_dispute(context); pass the instance when creating a pool or call it when resolving disputes. See API/policy for the built-in models and custom governance. For identity, verification, tool allowlists, timeouts, and deployment recommendations, see Security.
Recovery¶
Pool and task state are persisted in the Store used by PoolManager and TaskManager. On restart, create PoolManager and TaskManager with the same store (e.g. FileStore with the same path) so pools and tasks are restored. The inbox is not persisted; message replay is best-effort unless the transport supports it. The runtime’s optional checkpoint_store and checkpoint_interval_sec write a lightweight checkpoint (e.g. agent_id → last_activity_ts) for observability; they do not change processing or replay semantics.
Most runtime and policy components are configurable or replaceable (transport, inbox, scheduler, executor, admission, trust, governance, store, metrics, replay, tools). See Customization for a full list and how to plug in custom behavior.
For the full API and process model, see Architecture and the API reference.