Core

Job engine, ledger, guard evaluation, and resolution for running multi-agent consensus locally.

Overview

@consensus-tools/core is the protocol engine for consensus-tools. It provides the job lifecycle engine, token ledger, guard evaluation, and agent registry — everything needed to run multi-agent consensus without a network.

Installation

pnpm add @consensus-tools/core @consensus-tools/storage

Breaking change in v0.9.0

Storage classes (createStorage, JsonStorage, SqliteStorage, MemoryStorage, IStorage, Mutex) moved to @consensus-tools/storage. Import them from that package instead of @consensus-tools/core.

Quick start

LocalBoard bundles the job engine, ledger, and storage into a single entry point:

import { LocalBoard } from "@consensus-tools/core";
import { MemoryStorage } from "@consensus-tools/storage";
import type { ConsensusToolsConfig } from "@consensus-tools/schemas";

const config: ConsensusToolsConfig = {
  mode: "local",
  local: { storage: { kind: "memory" } },
} as ConsensusToolsConfig;

const storage = new MemoryStorage();
await storage.init();
const board = new LocalBoard(config, 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"]

API reference

LocalBoard

Bundles JobEngine, LedgerEngine, and IStorage into a single convenience class.

class LocalBoard {
  constructor(config: Config, storage: IStorage);
  init(): Promise<void>;
  engine: JobEngine;
  ledger: LedgerEngine;
}

JobEngine

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>;
}

LedgerEngine

Token accounting: faucet grants, staking, payouts, and slashing.

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");
const all = await ledger.getBalances(); // { "agent-1": 105, ... }

GuardEngine

Evaluates agent actions against guard policies, returning ALLOW, BLOCK, REWRITE, or REQUIRE_HUMAN.

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 },
});
// result.decision => "ALLOW" | "BLOCK" | "REWRITE" | "REQUIRE_HUMAN"

Storage backends

Storage classes are in @consensus-tools/storage:

import { createStorage, JsonStorage, SqliteStorage, MemoryStorage } from "@consensus-tools/storage";

// Direct instantiation
const jsonStore = new JsonStorage("./state.json");
const sqliteStore = new SqliteStorage("./state.db");
const memStore = new MemoryStorage();
await memStore.init();

// Config-driven factory (reads config.local.storage.kind)
const storage = await createStorage(config);

Resolution policies

Nine built-in resolvers are available as standalone functions:

import { resolveConsensus, firstSubmissionWins, approvalVote } from "@consensus-tools/core";

// Dispatches automatically based on job.consensusPolicy.type
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.

Decision explanation

Generate human-readable narratives for guard decisions (requires an LLM function):

import { explainDecision, guardResultToExplainInput, summarizeGuardActivity } from "@consensus-tools/core";

// Get a guard result from storage and convert it to an ExplainInput
const state = await storage.getState();
const guardResult = state.guardResults.find((r) => r.audit_id === auditId);
const input = guardResultToExplainInput(guardResult);

// Generate a plain-language narrative (requires an LLM function)
const result = await explainDecision(input, {
  llm: async (prompt) => { /* call your LLM here */ return response; },
  onPrompt: (prompt) => console.error("[debug prompt]", prompt), // optional
});
console.log(result.narrative);

// Summarize recent guard activity across all domains
const summary = await summarizeGuardActivity(storage, { since: "2026-01-01", limit: 20 });

Exports reference

ExportDescription
LocalBoardBundles JobEngine + LedgerEngine + IStorage
JobEnginePost, claim, submit, vote, resolve jobs
LedgerEngineFaucet, stake, unstake, payout, slash
GuardEngineEvaluate agent actions against guard policies
AgentRegistryCreate, suspend, scope-check agents
HitlTrackerHuman-in-the-loop approval tracking
computeBalances / getBalanceLedger balance computation helpers
resolveConsensusDispatch to policy by type
firstSubmissionWins, highestConfidenceSingle, approvalVote, ownerPick, trustedArbiter, topKSplit, majorityVote, weightedVoteSimple, weightedReputationIndividual policy resolvers
checkEligibilityCheck agent eligibility for a job
calculateSlashAmountCompute slash penalty
newId, deepCopy, nowIso, addSeconds, isPastUtilities
explainDecision, summarizeGuardActivityDecision explanation and audit summary
  • storage -- IStorage interface and storage backends (moved from core in v0.9.0)
  • policies -- pluggable policy registry that builds on core's resolvers
  • workflows -- DAG-based workflow engine that uses core's JobEngine
  • wrapper -- lightweight consensus gate for wrapping async functions