Minerval

← docs

Minerval Architecture

This document describes the Minerval system as it is built today: the domain model, the agent pipeline that populates it, the data layer underneath, and the surfaces that serve it. It is a description of the running architecture, not a roadmap. Where a design decision has interesting consequences, the reasoning is given inline.

The companion documents are the constitution, the text every administrator agent is bound by; the agents pages, which show each agent's actual system prompt verbatim; and the operational policies further down this page, which translate the constitution into concrete rules for each agent.


System Overview

Minerval turns documents into a queryable graph of claims. Ingestion is the expensive, write-side work: an LLM pipeline reads a source, pulls out atomic claims, decides whether each is new, decomposes it into its supporting structure, and assesses its validity. Serving is the cheap, read-side work: the graph is queried directly, with no LLM in the read path. The few surfaces that invoke agents on demand (submitting a source, the browser extension's page analysis, the MCP assessment tools) are authenticated, rate-limited, and metered per account.

   SOURCE               INGESTION                    GRAPH
 ┌─────────┐   ┌───────────────────────────┐   ┌───────────┐
 │ URL or  │──▶│ Extractor → Matcher →     │──▶│ Postgres  │
 │ document│   │ onboard → Claim Steward   │   │ + pgvector│
 └─────────┘   └───────────────────────────┘   └─────┬─────┘
                                                     │ read
   GOVERNANCE (ongoing)                              ▼
 ┌──────────────────────────────────────┐      ┌───────────┐     web ·
 │ Claim Steward (decompose + assess) · │◀────▶│    API    │──▶  extension ·
 │ Curator · Contribution Reviewer ·    │      │ (Fastify) │     MCP clients
 │ Dispute Arbitrator · Audit Agent     │      └───────────┘
 └──────────────────────────────────────┘

The work is done once, at ingestion, and reused everywhere a claim recurs: the same claim appears across thousands of documents but is decomposed and assessed a single time. Nor does every claim get the full treatment immediately. Each claim carries an importance score, and stewardship drains in importance order, so the most consequential claims are structured and assessed first while minor ones wait as searchable stubs.

The stack is TypeScript end to end: a Fastify API, background workers driven by a job queue (AWS SQS in production, an in-memory runner locally), and PostgreSQL with the pgvector extension as the single store, carrying vector search and full-text search alongside the relational data. Anthropic Claude models sit behind every agent; the client calls the Anthropic Messages API directly, model ids are centralized in src/llm/models.ts, and in production the load-bearing agents run on Claude Fable 5.


The Domain Model

Six entities carry the epistemic content. The rest of the schema records accounts and governance (contributors, contributions, reviews, appeals, arbitration, reputation) and operations (sources, jobs, usage metering). The epistemic core, where ──< reads "has many":

  Source ──< Instance >── Claim ──< Relationship >── Claim
                            │           (decomposition edge;
                            │            argument_id groups edges
                            │            into a line of reasoning)
                            ├──< Assessment   (verdict history; one is_current)
                            │
                            └──< Argument      (a named line of reasoning;
                                                relationship edges point back
                                                to it via argument_id)

Claims

A claim is the atomic unit: a proposition that can be true or false. Empirical claims (directly verifiable or derived), definitional, evaluative, causal, and normative claims are all represented the same way and all decompose into subclaims. Two formulations are the same claim when they turn on the same considerations: nothing could count as evidence or argument bearing on one without bearing equally on the other (identical decomposition is a useful diagnostic, not the definition). This is the basis for deduplication, and it extends to negation. A claim and its denial are one node, and each recorded appearance carries a stance saying which side it takes.

Each claim carries its canonical text, a claim_type, a lifecycle state (a claim merged into another records the target in merged_into rather than being deleted), counters for how many of its children have been assessed, an embedding (a 1536-dimension vector) and a text_search column for retrieval, and an importance score.

Importance is a 0 to 1 judgment of consequence-if-wrong times contestability. It is explicitly not a count of dependents: a settled fact cited everywhere scores low, a load-bearing contested premise scores high. The Extractor supplies a prior at ingestion; the claim's Steward sets the authoritative value once it has decomposed the claim and seen its neighborhood. Importance decides both how soon a claim is stewarded and how much effort its Steward spends.

Two further signals are recorded but not yet acted on (issue #172, phase 1 of splitting stakes from expected yield): contestation on the claim, how live the dispute is stated unfused from the consequence half, and marginal_yield on each assessment, the Steward's exit judgment of how much another, stronger pass would improve it. Queue order, the decomposition brake, and effort selection still read only the fused importance score; the follow-up phases in #172 will move scheduling to a function of both dimensions once these fields have accrued data.

Arguments

An argument groups decomposition edges into a coherent, named line of reasoning. A single claim routinely has several:

  • Philosophy: "God exists" has the cosmological argument, the teleological argument, the argument from evil, and others.
  • Policy: "We should raise the minimum wage" has a poverty-reduction argument (for) and an unemployment argument (against).
  • Science: "The universe is ~13.8 billion years old" is supported independently by the CMB, stellar evolution, and nucleosynthesis.

Forcing these into one flat set of edges would lose the structure of which subclaim belongs to which line of reasoning. An argument has a stance (for, against, neutral), an optional name and description (a short label), its content (the written form, below), any evidence_urls, and provenance.

The written form. A name is not an argument: the grouping records which subclaims belong together, but not how they combine to bear on the parent claim. Every named argument therefore carries a written form in content: one to three sentences of logically straightforward prose stating the inference, with every subclaim referenced inline as [[claim:<uuid>]] (or [[claim:<uuid>|inline phrasing]] when grammar demands it). For example: "Because [[claim:a]] and [[claim:b]], and given [[claim:c]], the claim follows." The links make the prose and the grouping mutually checkable: every subclaim edge in the argument should appear in the written form, and every reference must be an edge in the argument (the Steward's write_argument tool enforces the latter and warns on the former). Renderers resolve the ids to the claims' canonical text at display time, following merged_into, so links never dangle after a merge. The connective language that the claim bar expels from claim texts ("therefore", "because", "given that") lives here and only here.

The evaluation. The written form deliberately withholds judgment; the judgment lives in a separate steward-maintained evaluation (argument_evaluations, one is_current row per argument with prior rows kept as history). It records a verdict on the inference itself: holds, holds_with_caveats, fails, or contested (the framework's validity is itself live-disputed), plus two to four sentences of reader-facing prose saying whether the inference goes through granting its premises and which premises, given their current assessments, the argument lives or dies on, with those load-bearing premises linked inline exactly as in the written form. The evaluation is derived within the claim's assessment process, not as a fire-once verdict: the Steward's evaluate_argument tool stamps each evaluation with the assessment it was derived under, so an evaluation left behind by a later reassessment is detectably stale, and the assessment tool's result nudges the Steward to bring evaluations current whenever it records a new verdict.

Two design decisions follow:

  • The written form is structural; the evaluation is epistemic. The written form states the inference, never a verdict on whether it holds; the verdict and the load-bearing analysis live in the evaluation, which is maintained as part of the claim's assessment and follows the same transparency rules (reasoning visible, open to challenge). It is reader-facing prose, not a discussion surface: contributor exchanges stay in the contribution record.
  • Arguments are optional and non-exhaustive. A claim with one natural decomposition needs no explicitly named argument; edges simply carry a null argument_id. Admins create arguments when a line of reasoning is live in the discourse, not preemptively.

When the validity of an argument's framework is itself disputed in the discourse, "this framework is valid" is added as a subclaim within that argument, typically with an assumes relation, and the evaluation marks the verdict contested. The meta-dispute itself stays inside the claim layer, where decomposition, assessment, and contribution already operate.

Decomposition edges

Decomposition is recorded as claim relationships: directed edges from a parent claim to a child claim. Each edge has a relation_type, a free-text reasoning, a confidence, and an optional argument_id linking it to the argument it belongs to. A child can appear under multiple arguments (shared subclaims); a uniqueness constraint prevents duplicate parent/child/relation triples, and self-edges are rejected outright. The relation types are:

RelationMeaning
requiresThe child is a load-bearing premise: the parent is false without it.
supportsThe child provides evidence for the parent without being logically required.
contradictsThe child weighs against the parent.
specifiesThe child narrows or makes precise part of the parent.
definesThe child fixes the meaning of a term in the parent.
assumesBackground the parent's framing takes as given (often a framework or scope claim): if it fails the parent is ill-posed rather than simply false. Renamed from presupposes (#205).

Assessments

An assessment is a verdict on a claim at a point in time, and it is written for two audiences at once. The summary is the reader-facing verdict: a short paragraph, shown at the top of a claim page, saying what the evidence establishes and where the weight rests. The reasoning_trace is the audit record: how the evidence and decomposition were weighed, kept so the judgment can be reviewed, not so it can be read. Splitting them means neither has to compromise; a trace written to be skimmable makes a worse audit record, and an audit record shown to readers makes a worse summary.

Alongside these sit the status and confidence, a subclaim_summary snapshot of the children at judgment time, and the trigger (and trigger_context) that prompted the assessment. Assessments are append-only history: exactly one row per claim is flagged is_current, enforced by a partial unique index, so the timeline of why a claim's status changed is fully recoverable. The statuses and how they propagate are described under Assessment below.

Instances and sources

A source is a retrieved document (URL, title, content hash, raw content, type). An instance links a canonical claim to one place it actually appeared: the exact original_text quote, the surrounding context, a brief summary_context describing the circumstances ("said during a Senate hearing on banking regulation, in response to questioning about derivatives oversight"), a stance recording whether the quote affirms or denies the canonical claim, and a confidence that the quote really expresses it. Instances are how a single canonical claim accumulates provenance from many documents, and the stance field is what lets a claim and its negation share one node without losing track of who said which.

Contributions and governance

Anyone can contribute — but the graph is a governed space: open to suggestions, never to direct writes. A contribution targets a claim with a type (challenge, support, propose_merge, propose_split, propose_edit, add_instance, or propose_argument) plus content and evidence. Contributions flow through review (contribution_reviews), can be appealed (appeals), and escalated to arbitration (arbitration_results).

Two intake types extend the same machinery to brand-new content: propose_claim (a suggested claim plus its supporting argument) and propose_source (a document submitted for extraction). These have no target claim while pending — nothing touches the claims table — and only an accepted review materializes them: a proposed claim is canonicalized through the Matcher (so a duplicate or a negation lands on the existing node) and only then created live and handed to its Steward, with a deliberately conservative importance prior; a proposed source is only then queued for extraction. The review gate judges good faith and claim quality (is this a single, disputable, canonical-formable proposition?), never subject matter. Internal seeding by direct service callers (corpus runs, case studies) is the one path that writes without review.

Contributors are the account layer as well as the reputation layer; there is one account table, and everyone on it is a potential contributor. Reputation and kudos are kept as append-only event ledgers (reputation_events, kudos_events) with denormalized totals on the contributor row, so every score change traces back to the decision that caused it. Reviews can flag suspected bad faith, and a contributor's standing feeds back into how much their contributions are trusted. This is the machinery the governance agents operate; the rules they apply live in the operational policies below.


Assessment

The six statuses

Validity is expressed honestly, never as a binary. The system implements all six statuses the constitution defines:

StatusMeaning
verifiedTraces to reliable primary sources through a clear evidence chain.
supportedEvidence favors the claim, but the chain is incomplete or sources are secondary.
contestedCredible evidence or argument exists on multiple sides.
unsupportedNo credible evidence found, though the claim is not contradicted.
contradictedAvailable evidence actively weighs against the claim.
unknownInsufficient information to assess.

The colour treatment in the UI is deliberately muted and never a traffic light: supported and verified are distinct shades of green, contested is amber, contradicted is a clay red, and the rest are warm neutrals. Meaning never depends on colour alone.

Judgment-based propagation

Assessment is a holistic judgment by the claim's Steward, not a mechanical roll-up of child statuses. An earlier design used hard aggregation rules ("if any required subclaim is contested, the parent is contested"). At scale that makes contestation infectious: almost every claim eventually inherits a contested subclaim somewhere deep in its tree, and the status field becomes useless.

Instead, the Steward weighs the status of subclaims across all arguments, the materiality of each subclaim to the parent's truth, and the strength of each argument as a whole, and documents the result in its reasoning. The Steward prompt gives guidance and worked examples rather than rules, and is explicit: do not mechanically propagate status changes; assess materiality first.

Propagation is therefore self-limiting. When a Steward materially changes an assessment, it notifies the Stewards of directly dependent claims, each of which re-judges with the same materiality test. Most changes are absorbed within a level or two, because a superior claim is rarely the right locus for a dispute about one of its subclaims.


The Agent Pipeline

Each agent is a Claude model with a system prompt assembled in layers: the full constitution first, then the agent's specific role (governance roles also splice in the relevant operational policies). The assembled prompt is sent as a single cached block, so the constitution is paid for once per agent rather than once per call. The prompts live in src/llm/prompts/ and are vendored verbatim into this site (see the agents page).

Processing stage

Ingestion runs three steps before governance takes over:

 Extractor ──▶ Matcher ──▶ onboard ──▶ Claim Steward
  read a       new claim    latch +     decompose + assess
  source for   or existing? enqueue     (a governance agent,
  its claims  (agentic search           below)
              over the graph)
  • Extractor: reads a source and emits the discrete, reusable claims it asserts, in canonical form, each with a provisional importance prior and a confidence that the proposition is a well-formed claim at all. It is a structured extraction call rather than a tool-use loop, and it is deliberately selective: the claims a reader would want checked, not every sentence. A low confidence floor drops obvious non-claims before they enter the graph — a backstop against garbage, not a quality judgment, which stays with the agents.
  • Matcher: the single decider of claim identity. For each proposition it searches the graph itself, under multiple framings including the negation, and decides match-or-create, recording the stance of the new appearance. It is also a tool the Steward and Curator call before creating anything. Two claims match when the same considerations bear on both; identical decomposition is a diagnostic, not the test. If the Matcher cannot reach a decision within its iteration budget, it defaults to "novel, low confidence": the failure mode is a duplicate the Curator can merge, never a lost claim.
  • Onboarding is not an agent. A small dispatcher latches the new claim so redelivered messages cannot double-process it, then enqueues its Steward.

Decomposition and assessment are not separate processing agents: they are the Claim Steward's job, because deciding what a claim depends on and whether those dependencies hold is one open-ended judgment that belongs to the claim's owner.

Governance agents

These act through tools over the life of a claim and the graph:

  • Claim Steward owns a single claim end to end: it decomposes the claim (calling the Matcher before minting any subclaim, so existing claims are linked rather than duplicated), maintains its canonical form and arguments, sets its authoritative importance, and assesses it, re-judging as evidence and depended-on claims change. Its triggers: first onboarding, a subclaim's assessment changing, an accepted contribution, a Curator change, or a staleness check. Effort scales with importance; consequential or contested claims get deeper search (including bounded web search) and an adversarial second pass, minor settled ones a light touch. Decomposition terminates without a depth cap because shared ancestors get linked, not re-created; recursion is bounded economically by the importance brake, and a per-run cap on newly minted subclaims backstops a single runaway pass.
  • Curator is the graph-level counterpart: it owns the connective tissue between claims, merging duplicates and counterparts the Matcher missed, splitting conflated claims (§5), and suggesting cross-claim edges for the owning Stewards to adopt. It runs on Steward escalations and on sampled sweeps of the neighborhood around newly created claims. Every structural operation lands in an append-only reconciliation log with enough payload to reverse it, and the Curator never overrides a Steward's verdict.
  • Contribution Reviewer evaluates each incoming contribution against policy (accept, reject, or escalate), including propose_argument contributions, and flags suspected bad faith. It is also the graph's admission gate: user-proposed claims and sources arrive as intake contributions, and its accept — judged on good faith and claim quality, never topic — is what admits them (materialization itself is mechanical: Matcher first, then claim creation or extraction).
  • Dispute Arbitrator resolves escalations and appeals through careful adjudication, the highest-stakes governance call.
  • Audit Agent is quality control over the governance system itself. Each run is invoked with an audit type (a decision audit of specific review decisions, a pattern analysis across recent ones, a contributor review, or an anomaly investigation) and a free-text context saying what prompted it. Runs are fed from two directions: event triggers at the places suspicion is generated (every arbitration overturn and every bad-faith flag requests a decision audit, at most once per contribution), and a scheduler that requests a periodic sweep over recent decisions plus a re-examination of any suspension that has stood unexamined too long — both idempotent through a DB dedupe key, so concurrent processes never double-run an audit. Findings are persisted rows (audit_findings, attached to their audit_runs row), and every consequence — a re-review, a reputation adjustment through the ledger, a suspension — requires the finding that justifies it. A re-review first neutralizes the superseded decision's consequences (reputation, counters, kudos, a still-active bad-faith flag) so the fresh review's effects don't stack on the old ones. Audit suspensions are severe but not one-way: the suspended contributor can still appeal their own contributions, and the Arbitrator can lift a suspension whose basis an appeal dissolves.

One agent lives outside governance entirely. The Extension Agent is the read-only companion behind the browser extension: it judges the phrasings on a live web page against graph state (verdicts range from "egregious" to "fine") and powers the extension's chat, grounded in the same graph tools. It never writes to the graph.

Models

Model choice follows the stakes of the judgment, not a single default:

AgentProduction model
MatcherClaude Haiku 4.5
Extractor · Contribution Reviewer · Extension AgentClaude Sonnet 5
Claim Steward · Curator · Dispute Arbitrator · Audit AgentClaude Fable 5

The Matcher's judgment is narrow ("same proposition?") over candidates it retrieves itself, so a small model suffices. The load-bearing epistemic work (stewardship, structural adjudication, arbitration, audit) runs on Fable 5, with a server-side fallback to Opus 4.8 so a safety-classifier refusal degrades gracefully instead of failing the job. Because stewardship drains in importance order, the most capable model is always spent on the most load-bearing claims; when a budget caps a run, what goes unassessed is the tail.

Queues and failure handling

Ingestion and the governance pipelines ride SQS queues in production and an in-memory runner locally, with identical handlers. Stewardship is the exception: it has no message queue at all. The claim row is the queue; a steward-state column plus a partial index makes enqueueing idempotent (a claim re-triggered while already pending coalesces into one run), and workers drain it in importance order with FOR UPDATE SKIP LOCKED, so concurrent workers never collide.

Failures are classified before they are counted. Transient API errors (rate limits, server errors, network, exhausted budget) requeue the claim untouched and do not count as attempts, and a run of consecutive transient failures trips a circuit breaker that stops the drain rather than poisoning healthy claims. Only genuine logic errors count toward the retry cap, after which the claim parks in an error state for inspection. The distinction exists because an earlier incident parked dozens of production claims over what turned out to be a billing hiccup.


Persistence

PostgreSQL, not a graph database

The graph is stored relationally in PostgreSQL, accessed through Drizzle ORM, not in a dedicated graph database. Claims are rows; decomposition is an adjacency table (claim_relationships) whose argument_id column attaches each edge to its line of reasoning; arguments, assessments, instances and sources are their own tables. A relational store keyed by foreign keys is more than adequate for the tree-shaped reads the product needs, and it lets the same engine carry vector search and full-text search without a second system to operate.

Tree-building (src/services/tree-service.ts) walks the relationship table level by level with a visited set, so each node and edge is fetched exactly once even where shared subclaims give the DAG a diamond shape. The walk is bounded by a cap of 500 nodes per response (MAX_TREE_NODES); children dropped by the cap are flagged on their parent (children_truncated), never silently. Each edge's argument_id, argument_name, argument_stance, and argument_content are carried onto the node, so a client can group a claim's children by argument and render each argument's written form.

Schema at a glance

claims ──< claim_relationships >── claims     (parent / child adjacency)
  │              │
  │              └── argument_id ─▶ arguments ──▶ claims
  │                                    └──▶ argument_evaluations
  │                                         (inference verdicts; one is_current per argument)
  ├──▶ assessments        (verdict history; one is_current per claim)
  ├──▶ claim_instances ──▶ sources   (provenance: quote + context + stance)
  └──▶ contributions ──▶ contribution_reviews ──▶ appeals ──▶ arbitration_results
                              contributors ─┘

Around that core sit the account and operations tables: contributors doubles as the account table, api_keys holds hashed keys, llm_usage meters every model call, reputation_events and kudos_events are the append-only score ledgers, reconciliation_events is the Curator's reversible audit log, audit_log is the Steward's append-only decision trail, audit_runs and audit_findings are the Audit Agent's run ledger and durable findings (the run ledger doubles as the dedupe gate for audit triggers), and jobs tracks queued work.

Search: vectors and full text

Postgres carries both retrieval paths the pipeline needs. Each claim has a 1536-dimension embedding (a pgvector column) for semantic neighbour search and a tsvector column for keyword search. A query runs both recall paths at once: a claim is a candidate if it matches the keyword query or falls within embedding range. The two signals are deliberately not blended into one score; results are ordered by cosine similarity, with keyword rank as a tiebreak, and keyword matching serves to widen recall. If embedding generation fails, search degrades to keyword-only. Every path serves only active, unmerged claims. This hybrid search serves the public search API, the MCP search_claims tool, and the agents' general search tool. The Matcher's candidate retrieval is the exception: it uses embedding similarity alone, with a deliberately low floor, and widens recall by re-searching under multiple framings rather than by keyword rank.


Serving Surfaces

The API

A Fastify service at api.claimgraph.io. Reads are public and unauthenticated: claim lookup and search, decomposition trees, dependents, assessment history, contributor profiles. Anything that writes or spends model tokens (POST /sources, POST /claims/propose, contributions, appeals, the extension and MCP endpoints) requires a key. No user surface writes to the graph directly: proposed claims and submitted sources become pending intake contributions (HTTP 202) for the Contribution Reviewer, and only direct service callers — internal seeding — keep the immediate path. Interactive OpenAPI documentation is served at /docs on the API host.

The web app

This site, a Next.js app at minerval.ai. It talks to the API server-side with a service key, forwarding the signed-in user's identity through an acting-user header, so browser traffic never carries API credentials.

The browser extension

The extension analyzes the page you are reading: captured text flows through the Extractor and Matcher, then the Extension Agent judges each on-page claim against graph state and the verdicts are anchored as a non-destructive overlay, with a chat popup grounded in the same graph. Analysis answers immediately when the page was analyzed before; otherwise it returns a content hash the extension polls until the pipeline finishes. The work is metered to the user's account, and the key lives in the extension's background worker, never in the page.

MCP

A remote MCP server, speaking streamable HTTP at POST /mcp on the API host, exposes the graph to agentic clients under the same accounts and quotas: tools for searching and reading claims (search_claims, get_claim, get_decomposition), for the pipeline's judgments (match_claim, extract_claims, assess_text), and for contributing (submit_contribution, get_contribution_status), plus claim resources and fact-checking prompts. Clients authenticate with an API key or via the OAuth 2.1 authorization flow — the API acts as an authorization server for the /mcp resource, handing sign-in and consent to the web app — which is what lets hosted clients such as Claude.ai connect. Every call is attributed to an account either way.


Accounts, Keys, and Metering

Users and contributors are the same thing: one account table, one identity. Sign-in on the web app goes through Auth.js (GitHub or Google); the API never sees OAuth, only a stable external id of the form provider:subject, against which the account is provisioned on first sign-in.

API keys are prefixed epk_, stored only as hashes, shown once at creation, and scoped user or service. Every model call in the system is metered at the LLM client chokepoint: tokens are priced into micro-USD and recorded per agent, user, and key. Quota enforcement is two gates at the API boundary, a sliding-hour rate limit and a monthly grant; exceeding the grant returns a payment-required error. Billing behind the grant is a deliberate seam: the free tier is the only provider wired in today, and a paid provider can be swapped in without touching the metering.


Deployment

The API runs as a container on ECS Fargate behind an application load balancer at api.claimgraph.io, with RDS PostgreSQL (pgvector) and SQS, all provisioned by CDK; a push to main deploys after typecheck and tests, and migrations run at container start. The web app deploys separately to Vercel at minerval.ai. Local development uses docker-compose Postgres and the in-memory queue runner, so the whole pipeline runs on a laptop with no AWS dependencies.


Evaluation

The pipeline is graded against fixed corpora, not eyeballed. A harness runs the real application (real routes, real workers, drained to quiescence) over curated clusters of source documents and records every agent message. An LLM judge, deliberately a different model from the agent under test, then scores the assessed claims against the constitution on axes like readability, reasoning fit, impartiality, and decomposition granularity. Runs are compared release over release, so prompt and model changes are judged by what they do to the graph, not by how they read.


The operational policies that follow turn the constitution's principles into concrete, per-agent rules: the shared policy vocabulary every governance decision cites, the acceptance criteria the Contribution Reviewer applies, and the reasoning obligations every agent carries.


Operational policies

Minerval Agent Policies

This document is the operational layer between the Admin Constitution and the agents that run the graph. The constitution carries the doctrine; these policies turn it into working definitions and per-role decision criteria that the governance agents cite by name when they decide. Where a policy and the constitution appear to diverge, the constitution wins, and the policy needs fixing.

The authoritative text of the policy blocks, exactly as the agents receive them, lives in src/llm/prompts/policies.ts and is embedded verbatim in each governance agent's system prompt. The agents pages show the assembled prompts. This document explains the same material for readers.


Prompt Architecture

Every admin agent's prompt follows this structure:

┌─────────────────────────────────────────────┐
│ LAYER 1: Admin Constitution (cached)        │
│ - Full text of admin_constitution.md        │
│ - Identical across all admin agents         │
│ - Establishes epistemic principles          │
└─────────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────┐
│ LAYER 2: Role-Specific System Prompt        │
│ - Defines the agent's specific role         │
│ - Governance roles splice in the shared     │
│   policy vocabulary and their role's        │
│   policy block                              │
│ - Specifies tools and output requirements   │
└─────────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────┐
│ LAYER 3: Task Context                       │
│ - The specific claim/contribution/dispute   │
│ - Relevant graph context                    │
│ - Conversation history (if applicable)      │
└─────────────────────────────────────────────┘

The constitution is read from admin_constitution.md at load time and the process fails loudly if the file is missing; there is no fallback summary, because a prompt silently missing its first layer would be worse than a crash. The assembled prompt is sent as a single cached block, so the constitution is paid for once per agent rather than once per call.

This architecture ensures:

  • Consistent application of epistemic principles across all agents
  • Clear separation between "how to think" (constitution) and "what to do" (role)
  • Efficient caching of the constitution text across agent invocations

The Shared Policy Vocabulary

Seven core policies form the shared vocabulary of governance decisions. Agents cite them by name or letter code; the constitution grounds each of them, and they are working definitions rather than separate law.

  • Verifiability (V): Factual assertions offered to the graph must come with evidence a reviewer can follow to its source. "BLS reported X" is verifiable; "everyone knows X" is not.
  • Neutral Decomposition (ND): Decomposition reveals structure; it does not impose a side. Subclaims cover all significant positions, inconvenient dependencies included, and contested subclaims are presented as contested.
  • Source Weight (SH): Evidence is weighed by what the source indicates about it: directness, methods, review. Primary evidence outweighs reports of it, and contested claims demand the strongest evidence available. Weight is judged, not read off a rank.
  • No Origination (NOR): Claims enter the graph from the discourse: neither contributors nor admins mint propositions no source asserts. This bounds what may be added, never how deeply admins may analyze; direct assessment on the merits is the method (constitution §9).
  • Faithful Interpretation (CI): Read contributions as their author most plausibly meant. Distinguish unclear writing from bad argument, and consider whether clarification would fix what rejection would punish.
  • Explicit Uncertainty (EU): Never manufacture confidence. Contested is contested; lack of evidence is not evidence of absence; assessments acknowledge their limits.
  • Process Over Outcome (PO): The same process for every claim and every contributor, however obvious the conclusion looks. Deviations matter even when the outcome happens to be right.

Two of these deserve a note on what they do not say, because both descend from Wikipedia-shaped ancestors that the constitution supersedes:

  • NOR is a contribution gate, not an analysis limit. Wikipedia's no-original-research policy makes its editors summarizers; the graph's admins are trusted with substance (constitution, Preamble and §9). They open primary sources, run their own analysis, and record verdicts on the merits. What NOR forbids is minting propositions that no source asserts, by contributors and admins alike; it says nothing about how deeply an admitted claim may be assessed.
  • SH weighs authority as evidence, not as rank. There is no tier ladder in which a source's type settles its weight. Credentials, peer review, and institutional backing raise the likelihood that sound methods were used, and a large convergent literature is among the strongest forms of evidence there is; the admin weighs all of this for what it indicates without deferring to it absolutely (§9).

Role Policies

Each governance agent receives the shared vocabulary above plus a policy block for its own role. What follows summarizes those blocks; the embedded text is in src/llm/prompts/policies.ts and on each agent's page.

Claim Steward

The Steward owns a single claim's page end to end: canonical form, decomposition, arguments, and assessment (Part VIII). Its role prompt carries the operational detail; the policy commitments underneath it:

  • Keep the canonical form the shortest neutral statement of the proposition as actually debated (§3), improving wording on its merits rather than preferring whichever formulation arrived first (§2).
  • Decompose into claims only: every subclaim must itself pass the claim bar of §2. Derivations, undisputed definitions, and source-specific facts live in prose (an assessment or an argument's written form), never as nodes (§6).
  • Never mint a subclaim without asking the Matcher whether it already exists, under any wording or as its negation (Part VIII).
  • Scale effort with importance (§19): a live crux earns deep structure and broad evidence search; a settled minor claim gets a light, careful pass.
  • Assess directly on the merits (§9), reaching a holistic verdict across all arguments rather than mechanically aggregating subclaim statuses, and re-judge when evidence or depended-on claims change (§22). Propagation is a judgment at both ends, not a cascade.

Contribution Reviewer

The Reviewer is the gate through which outside contributions enter, including intake: user-proposed claims and sources are admitted by its accept and by nothing else. Its policy block sets:

  • Acceptance criteria by type. A challenge must name a specific flaw or bring followable counter-evidence (V); support must bear on this claim and add something new; a merge case must show the two claims turn on the same considerations (§2); a split case must show conflation of propositions that turn on different considerations; an edit must preserve the claim's identity while moving toward §3's canonical form; an instance must be accurately quoted and fairly contextualized (§4); an argument must be a coherent line of reasoning with relevant, connected subclaims (§7). Accepting a structural proposal admits the case for it, not the change itself: the owning admins adjudicate and apply it (§5, Part VIII).
  • The intake gate is form, good faith, and the claim bar, never topic (§17). A false or unsettled claim can still be worth mapping; a proposition of the contributor's own coinage that no source asserts fails NOR. Novelty is the Matcher's call: acceptance materializes through it, so a likely duplicate is still acceptable if well formed.
  • The bad-faith flag (§13) is a separate and heavier judgment than finding a contribution wrong: reserved for deliberate abuse (spam, vandalism, sybil activity, fabricated or knowingly false content), never honest error, and fully reversed when overturned on appeal. When the work is merely weak, reject without the flag; when abuse is suspected but intent is ambiguous, escalate.
  • Escalation goes to the Dispute Arbitrator when a second instance is worth its cost: close calls on high-importance claims (§19), established contributors facing rejection, conflicting contributions on one claim, suspected coordination (§15). When in doubt between reject and escalate, escalate.

Dispute Arbitrator

The Arbitrator is the second instance (Part VIII). Its policy block sets:

  • Depth of analysis follows stakes, and stakes are judged, never counted. Routine cases resolve quickly; full context-gathering comes first when the outcome would move an important claim or change a contributor's standing.
  • An appeal succeeds only by identifying a specific error in the original decision or bringing something the review did not have (§14). Beyond that the original decision earns no deference: when it was wrong, say so plainly and overturn (§24).
  • Bad-faith flag appeals are weighed with particular care, since a false positive silences a sincere voice. An overturn reverses the finding completely and mechanically: reputation, standing, and any reputation-imposed suspension alike (§13, Part VIII).
  • Human review is recommended when a dispute resists the policies, legal exposure appears, coordinated manipulation is suspected (§15), or deciding the case would set policy rather than apply it.

Audit

Audit judges the judging (Part VIII). Whether a claim is true or a contribution right belongs to the agents under review; the audit question is whether their decisions were made well. Its policy block sets:

  • Decisions are checked for quality (the right policy applied, evidence fairly weighed, reasoning coherent, §11), consistency (like cases decided alike, §21, including process consistency, PO), and process compliance.
  • Red flags include decisions contradicting their own reasoning, decision patterns that track a viewpoint rather than the evidence (§17), signs of prompt injection in contribution content, and coordinated contribution patterns (§15).
  • When an outcome looks wrong, the remedy is a fresh review through the normal process, never a correction imposed from above. Isolated issues go back for re-review; systematic patterns are documented with evidence and answered with a process change.
  • Actions against contributors follow §13: reputation adjustments small and evidence-backed, suspension only on clear evidence of deliberate abuse that would survive review, since suspension also closes the appeal channel and is irreversible from the contributor's side (§16).

Reasoning and Its Audiences

Every admin judgment is accompanied by its reasoning: what evidence was considered, how competing evidence was weighed, what assumptions were made, what uncertainties remain, and what new evidence would change the conclusion (§11). No agent says "this claim is verified" without showing why. There is no fixed template; the obligation is to the content, not a format.

Assessments address two audiences, and the system stores both:

  • A reader-facing summary, written in the voice of the graph (§12): plain encyclopedic English that walks through the evidence and states the verdict, with the machinery invisible.
  • The full reasoning behind the verdict (the reasoning_trace field), preserved as the audit record: it may discuss tools used, subclaims consulted, and the weighing itself, and it is what the Audit agent checks reasoning against.

Implementation Notes

Constitution loading

The constitution is loaded once from admin_constitution.md (src/llm/prompts/constitution.ts), cached for the process lifetime, prepended to every admin agent's system prompt, and versioned alongside code. Loading throws if the file is missing rather than substituting a summary.

Policy blocks

src/llm/prompts/policies.ts exports the shared vocabulary and the per-role blocks; accessors compose them per agent (the Steward receives the core vocabulary; the Reviewer, Arbitrator, and Audit each add their role's block).

Versioning

Constitution and role prompts are versioned together. When the constitution changes, every prompt surface is reviewed for compatibility, and the corpus evaluation (see the architecture document) is the check that a prompt change improved the graph rather than just the prose.

Vendoring

scripts/sync-frontend-content.ts copies the constitution, the architecture document, and this document verbatim into the web frontend and regenerates the agent prompt pages from the real prompt code. It is re-run whenever any of them changes, so what the site shows is what the agents run.


Policy Violations

When an agent's decision violates a policy:

  1. Audit detection: the Audit agent flags the violation, citing the specific policy
  2. Re-review: the decision is sent back for a fresh review through the normal process
  3. Learning: if the violation is systematic, the remedy is a documented process change, not a quiet correction

Violations are not failures of the agent but signals that the system needs attention. The goal is improvement, not punishment.