@consensus-tools/core is the foundation of the consensus-tools stack. It provides the job lifecycle engine, token ledger, storage backends, guard evaluation, and agent registry -- everything needed to run multi-agent consensus without a network.
pnpm add @consensus-tools/core
LocalBoard bundles the job engine, ledger, and storage into a single entry point:
import { LocalBoard, createStorage } from "@consensus-tools/core";
import { defaultConfig } from "@consensus-tools/schemas";
const storage = await createStorage(defaultConfig);
const board = new LocalBoard(defaultConfig, storage);
await board.init();
// Post a job
const job = await board.engine.postJob("agent-1", {
title: "Review this PR",
reward: 10,
stakeRequired: 1,
});
// Claim, submit, resolve
await board.engine.claimJob("agent-2", job.id, { stakeAmount: 1, leaseSeconds: 3600 });
await board.engine.submitJob("agent-2", job.id, {
summary: "Looks good",
confidence: 0.9,
});
const resolution = await board.engine.resolveJob("agent-1", job.id);
console.log(resolution.winners); // ["agent-2"]
Bundles JobEngine, LedgerEngine, and IStorage into a single convenience class.
class LocalBoard {
constructor(config: Config, storage: IStorage);
init(): Promise<void>;
engine: JobEngine;
ledger: LedgerEngine;
}
Manages the full job lifecycle: post, claim, submit, vote, and resolve.
class JobEngine {
constructor(storage: IStorage, ledger: LedgerEngine, config: Config);
postJob(agentId: string, opts: PostJobOpts): Promise<Job>;
claimJob(agentId: string, jobId: string, opts: ClaimOpts): Promise<void>;
submitJob(agentId: string, jobId: string, submission: Submission): Promise<void>;
vote(agentId: string, jobId: string, vote: VoteOpts): Promise<void>;
resolveJob(agentId: string, jobId: string): Promise<Resolution>;
listJobs(filter?: JobFilter): Promise<Job[]>;
getStatus(jobId: string): Promise<JobStatus>;
}
Token accounting: faucet grants, staking, payouts, and slashing.
class LedgerEngine {
constructor(storage: IStorage, config: Config);
faucet(agentId: string, amount: number): Promise<void>;
stake(agentId: string, amount: number, jobId: string): Promise<void>;
payout(agentId: string, amount: number, jobId: string): Promise<void>;
getBalance(agentId: string): Promise<number>;
getBalances(): Promise<Record<string, number>>;
}
const ledger = new LedgerEngine(storage, config);
await ledger.faucet("agent-1", 100);
await ledger.stake("agent-1", 5, job.id);
await ledger.payout("agent-1", 10, job.id);
const balance = await ledger.getBalance("agent-1");
Evaluates agent actions against guard policies, returning ALLOW, BLOCK, or ESCALATE.
class GuardEngine {
constructor(opts: { storage: IStorage; agentRegistry: AgentRegistry });
evaluate(input: GuardInput): Promise<GuardResult>;
}
const guard = new GuardEngine({ storage, agentRegistry: registry });
const result = await guard.evaluate({
agentId: "bot-1",
action: { type: "code_merge", payload: diff },
});
// result.decision => "ALLOW" | "BLOCK" | "ESCALATE"
Create, suspend, and scope-check agents.
class AgentRegistry {
constructor(storage: IStorage);
createAgent(agent: AgentDef): Promise<void>;
}
Factory that returns JsonStorage or SqliteStorage based on config.
function createStorage(config: Config): Promise<IStorage>;
Dispatches to the appropriate policy resolver based on job.consensusPolicy.type.
function resolveConsensus(input: ResolveInput): ResolveResult;
import { createStorage, JsonStorage, SqliteStorage } from "@consensus-tools/core";
// Auto-create from config
const storage = await createStorage(config);
// Or instantiate directly
const jsonStore = new JsonStorage("./state.json");
const sqliteStore = new SqliteStorage("./state.db");
import { GuardEngine, AgentRegistry } from "@consensus-tools/core";
const registry = new AgentRegistry(storage);
await registry.createAgent({
id: "bot-1",
name: "Bot",
kind: "internal",
scopes: ["code_merge"],
});
const guard = new GuardEngine({ storage, agentRegistry: registry });
const result = await guard.evaluate({
agentId: "bot-1",
action: { type: "code_merge", payload: diff },
});
Nine built-in resolvers are available as standalone functions:
import { resolveConsensus, firstSubmissionWins, approvalVote } from "@consensus-tools/core";
const result = resolveConsensus({ job, submissions, votes, reputation });
ℹPolicy dispatch
resolveConsensus reads job.consensusPolicy.type and dispatches to the matching resolver automatically. For a pluggable registry with custom policies, see the policies package.
- policies -- Pluggable policy registry that builds on core's resolvers
- workflows -- DAG-based workflow engine that uses core's JobEngine and storage
- wrapper -- Lightweight consensus gate for wrapping async functions