mmaridocs
GitHub ↗
mari-components · 0.1.0.dev0

Mari documentation

Mari is a framework-neutral Python library for building knowledge systems from changing source material. It supplies immutable domain types, connector contracts, synchronization planning, multi-vector and graph retrieval, rank fusion, memory update plans, topic segmentation, evidence validation, freshness tracking, workflow reuse, trajectory analysis, and verification utilities.

Current — implemented Proposed — planned, not released

How to read this page

“Current” sections describe importable code in mari_components. “Proposed” sections describe concrete interfaces and algorithms that are not released. Each research-derived mechanism links its evidence next to the explanation; library boundaries and failure behavior are labeled as Mari engineering contracts.

Install

Python 3.11–3.13 is supported. NumPy is the only runtime dependency.

terminal
pip install mari-components

# Optional runtime adapters
pip install 'mari-components[openai-agents]'
pip install 'mari-components[langchain]'

How it works

The base wheel installs the domain, connector, synchronization, retrieval, knowledge, trajectory, and verification modules without a model SDK or database client. Extras add adapter imports only; applications still inject model calls, HTTP transport, persistence, clocks, and authorization decisions. This is package behavior, not a research-derived algorithm.

Architecture

Values cross explicit boundaries. Mari plans and validates; the application performs side effects.

Sourcesprovider APIs
poll
Documentsidentity · revision · ACL
derive
Knowledgefacts · answers · decisions
retrieve
Contextallowed · fresh · cited
Mari suppliesApplication supplies
Typed values and pure planning functionsDatabase and transactions
Connector polling and cursor contractsCredentials, HTTP transport, retries, scheduler
Strict parsers for generated valuesModel, prompts, and inference
Retrieval and index serializationEmbeddings and index lifecycle
Policy and evaluation functionsAuthorization and agent runtime

How it works

Provider data is normalized into immutable values. Pure functions transform those values into plans, candidates, reports, or index payloads. The caller validates the return value and commits it through its own transaction boundary. Because network and storage operations are injected, the same input values can be replayed in tests before any side effect occurs.

Research and standards

W3C PROV data modelData pipeline reproducibility

Provenance and reproducibility motivate explicit entities, revisions, activities, and captured configuration. The pure-planning/application-commit split is a Mari engineering contract.
Current APIAvailable in mari-kit today

Documents, identity, and ACLs

KnowledgeDocument is the canonical provider-owned record. Its stable ID is {source_id}/{external_id}. Domain values are frozen dataclasses.

How it works

source_id names one configured source; external_id is the provider’s stable object key. Their pair prevents two providers from colliding. revision identifies content version, while updated_at is descriptive metadata and is never used as identity. ACL visibility and principals travel with the document so an allowed-ID set can be computed before retrieval scoring. Frozen values prevent an indexed object from changing behind its recorded revision.

document.py
from mari_components import DocumentACL, KnowledgeDocument, Principal

doc = KnowledgeDocument(
    source_id="github:acme/product",
    external_id="file:docs/refunds.md",
    title="Refund policy",
    body="## Enterprise\nRefunds close after 30 days.",
    revision="8f31c2a", updated_at="2026-08-31T10:00:00Z",
    source_url="https://github.com/acme/product/blob/main/docs/refunds.md",
    acl=DocumentACL(visibility="restricted", principals=(
        Principal(kind="team", identifier="support"),
    )),
    metadata={"path": "docs/refunds.md"},
)
assert doc.document_id == "github:acme/product/file:docs/refunds.md"
PollPage

Upserts, tombstones, cursor, checkpoint, snapshot completeness, provider metadata.

Tombstone

Explicit deletion by source and external ID.

KnowledgeSection

Stable section ID, offsets, text, and section revision.

Evidence

Exact quote plus document, revision, span, and optional section coordinates.

Research and standards

W3C PROV: entity identity and revisionZanzibar: relationship-based authorization

Mari carries principals and visibility but does not implement an authorization engine. The application resolves those fields to allowed_document_ids.

Polling and streaming connectors

Every connector defines a frozen configuration object, validation, and polling. GitHub, Slack, Google Drive, and Confluence also accept verified provider events. Network calls use an injected HttpTransport.

How it works

A polling connector starts from the caller’s cursor, requests bounded pages, normalizes provider objects, emits explicit tombstones, and returns the next cursor/checkpoint. A streaming connector verifies the raw delivery before parsing it, reduces provider payloads to bounded ChangeHint keys, coalesces duplicates, and canonically refetches the object. Both routes produce PollPage, so event order, partial webhook payloads, and provider retry behavior cannot bypass synchronization invariants.

GitHubSlackGoogle DriveConfluenceDropboxNotionAirtableAsanaJiraLinearTrelloZendesk
Scheduled pollPollRequest · cursor · checkpoint
Canonical PollPageupserts · tombstones · revision
plan_syncone persistence path
Provider streamraw body · headers
verify + parse
ChangeHintbounded · coalesced
canonical refetch
PollPagesame synchronization path

Provider examples

All polling functions accept the same PollRequest and injected HttpTransport, and return an iterator of PollPage values.

GitHub

Files, issues, pull requests, and commits.

from mari_components.connectors import GitHubConfig, poll_github
cfg = GitHubConfig(token=token, repository="acme/product",
    branch="main", paths=("docs/**",),
    content_types=("files", "issues", "pull_requests"))
pages = poll_github(cfg, request, http=http)

Slack

Channels, DMs, and canonical thread documents.

from mari_components.connectors import SlackConfig, poll_slack
cfg = SlackConfig(bot_token=bot_token,
    history_token=history_token, channels=("C0123",))
pages = poll_slack(cfg, request, http=http)

Google Drive

Drive files, Google Docs, changes, and push watches.

from mari_components.connectors import GoogleDriveConfig, poll_google_drive
cfg = GoogleDriveConfig(access_token=token, folder_id="folder-id")
pages = poll_google_drive(cfg, request, http=http)
# poll_google_drive_changes(...) and start_google_drive_watch(...)

Confluence

Cloud pages converted from storage HTML to Markdown-like text.

from mari_components.connectors import ConfluenceConfig, poll_confluence
cfg = ConfluenceConfig(site_url="https://acme.atlassian.net/wiki",
    email="bot@acme.com", api_token=token, space_key="ENG")
pages = poll_confluence(cfg, request, http=http)

Dropbox

Native delta cursor with explicit deleted entries.

from mari_components.connectors import DropboxConfig, poll_dropbox
cfg = DropboxConfig(token=token, path="/Knowledge")
pages = poll_dropbox(cfg, request, http=http)

Notion

Page search and bounded block-tree ingestion.

from mari_components.connectors import NotionConfig, poll_notion
cfg = NotionConfig(token=token)
pages = poll_notion(cfg, request, http=http)

Airtable

Base metadata and table snapshots.

from mari_components.connectors import AirtableConfig, poll_airtable
cfg = AirtableConfig(token=token, base_id="appABC123")
pages = poll_airtable(cfg, request, http=http)

Asana

Workspace or project tasks with offset checkpoints.

from mari_components.connectors import AsanaConfig, poll_asana
cfg = AsanaConfig(token=token, workspace_gid="workspace-gid",
    project_gid="project-gid")
pages = poll_asana(cfg, request, http=http)

Jira

Cloud issues with project or custom JQL scope.

from mari_components.connectors import JiraConfig, poll_jira
cfg = JiraConfig(site_url="https://acme.atlassian.net",
    email="bot@acme.com", api_token=token, project_key="SUP")
pages = poll_jira(cfg, request, http=http)

Linear

Issues and comments through the GraphQL API.

from mari_components.connectors import LinearConfig, poll_linear
cfg = LinearConfig(api_key=api_key, team_id="team-id")
pages = poll_linear(cfg, request, http=http)

Trello

Open boards, lists, and cards.

from mari_components.connectors import TrelloConfig, poll_trello
cfg = TrelloConfig(api_key=api_key, token=token)
pages = poll_trello(cfg, request, http=http)

Zendesk

Guide articles with ordered page checkpoints.

from mari_components.connectors import ZendeskConfig, poll_zendesk
cfg = ZendeskConfig(subdomain="acme",
    email="bot@acme.com", api_token=token)
pages = poll_zendesk(cfg, request, http=http)
connector.py
from mari_components import PollRequest
from mari_components.connectors import GitHubConfig, poll_github, validate_github

config = GitHubConfig(token=token, repository="acme/product",
    paths=("docs/**",), content_types=("files", "issues"))
validation = validate_github(config, http=http)
request = PollRequest(cursor=saved_cursor, page_size=100, page_limit=20)

for page in poll_github(config, request, http=http):
    consume(page)

Streaming

stream_pages requires a verifier, rejects oversized deliveries and batches, parses provider-specific hints, coalesces repeated aggregate keys, and calls an injected hydration function. The application owns the webhook server, queue, acknowledgement, and retries.

stream.py
from mari_components.connectors import StreamEvent, stream_pages

event = StreamEvent(provider="slack", raw_body=raw_body, headers=headers)

def hydrate(hint):
    document, complete = fetch_slack_thread_by_id(config,
        hint.metadata["channel"], hint.metadata["thread_timestamp"], http=http)
    return (PollPage(upserts=(document,) if document else (),
        snapshot_complete=complete),)

for page in stream_pages((event,), verify=verify_signature, hydrate=hydrate):
    consume(page)

Connector-specific capabilities

  • All twelve connectors: polling, validation, pagination limits, normalized documents, and explicit deletion handling.
  • GitHub, Slack, Google Drive, and Confluence: verified streaming change hints plus canonical refetch.
  • Slack: canonical thread fetch by ID.
  • Google Drive: native Changes polling and push-watch registration.
  • Confluence: direct canonical page fetch.
  • ConnectorDefinition.supports(ConnectorMode.POLL | STREAM) exposes mode capabilities for setup UIs.
Standards and protocol basis

OpenAPI: HTTP operation contractsCloudEvents: event envelopesRFC 2104: HMAC verification

Provider pagination, cursor, and signature schemes differ. Mari normalizes their observable results; it does not claim a universal delivery guarantee.

Synchronization

plan_sync compares a durable SyncState with one PollPage and returns a side-effect-free SyncPlan. stream_sync applies the same rules across pages.

How it works

For each upsert, Mari validates source ownership and compares a deterministic content fingerprint with the manifest: equal means unchanged; unequal means upsert. Explicit tombstones always become deletes. Absence becomes deletion only after the terminal page of an authoritative full snapshot. The returned plan carries the prior generation as a compare-and-swap precondition and the next manifest/cursor as proposed state; persistence must atomically commit both data and state.

Startgeneration 41
Pagesupsert · tombstone · unchanged
Complete?no: preserve missing docs
Reconcileyes: absence may delete
CommitCAS generation 42
sync.py
from mari_components import SyncMode
from mari_components.sync import SyncState, plan_sync

state = load_state() or SyncState()
for page in provider_pages:
    plan = plan_sync(state, page,
        source_id="github:acme/product", mode=SyncMode.FULL)
    store.commit(upserts=plan.upserts, deletes=plan.deletes,
        state=plan.state, expected_generation=plan.expected_generation)
    state = plan.state

Enforced invariants

  • Page replay is idempotent through content fingerprints and manifests.
  • Only terminal, authoritative full pages reconcile absence.
  • Explicit tombstones apply in full and incremental modes.
  • Incomplete full sync cannot resume as incremental.
  • Generation compare-and-swap prevents concurrent state loss.
  • Foreign source IDs, duplicate IDs, and upsert/delete overlap are rejected.
Research basis

Build Systems à la Carte: fingerprints and minimal rebuildsDynamo: versioning and reconciliation

Snapshot authority, deletion rules, and atomic compare-and-swap are Mari’s connector/store contract.

Multi-vector retrieval

Mari implements MUVERA fixed-dimensional candidate generation, PolarQuant compression, and exact normalized MaxSim reranking in one retrieval path.

Query token vectors
MUVERA
Candidate documentsallowed IDs only
exact MaxSim
RetrievalHit[]ranked + scored
retrieve.py
from mari_components.retrieval import FDEConfig, build_index, search_index

index = build_index({doc.document_id: token_vectors},
    config=FDEConfig(repetitions=20, projection_dimension=16))
hits = search_index(index, query_token_vectors, limit=8,
    allowed_document_ids=authorized_document_ids)

serialize_index and deserialize_index use versioned, checksummed payloads. exact_maxsim is public for direct scoring.

How it works and backing algorithms

Mari's current path uses token-level late interaction: each query token takes its maximum similarity to any document token, and the maxima are summed. MUVERA maps those multi-vector sets to fixed-dimensional encodings for fast candidate generation; Mari then reranks the candidates with exact MaxSim. The packed Polar codec is an implementation-level compression of candidate encodings, not an alternative relevance model.

StatusIndex familyRepresentation and algorithmAppropriate whenPrimary source
CurrentMUVERA + exact MaxSimMulti-vector FDE candidate generation, compressed storage, exact late-interaction rerankingFine-grained semantic matching where individual query terms matterMUVERA · ColBERT
ProposedDense flatExact cosine, dot-product, or L2 scan over one vector per passageSmall corpora, evaluation baselines, or exact reproducibilityDense Passage Retrieval
ProposedHNSWHierarchical proximity graph for approximate nearest-neighbor searchLarge mutable dense-vector collections with low-latency queriesHNSW
ProposedIVF-PQCoarse inverted partitions plus product-quantized vector codesMemory-constrained or very large dense indexesProduct Quantization · Faiss
ProposedBM25Probabilistic lexical ranking over an inverted term indexExact names, identifiers, code symbols, and domain terminologyBM25 and Beyond
ProposedLearned sparseTransformer-produced sparse term weights served by an inverted indexLexical interpretability with learned expansionSPLADE
CurrentRank fusionWeighted reciprocal-rank fusion over independent result lists, with per-source contribution tracesMixed corpora where source scores are not directly comparableRAG-Fusion
CurrentGraph propagationAllowed-node personalized PageRank followed by weighted node-to-passage projectionMulti-hop recall from query-linked entities, facts, or sectionsHippoRAG

Proposed index interface

The common protocol should describe capabilities rather than a vendor. Index selection then becomes pipeline configuration and can be evaluated against recall, latency, memory, freshness, and ACL-filter behavior.

proposed / indexes.py
indexes = {
    "exact": DenseFlatIndex(metric="cosine"),
    "dense": HNSWIndex(metric="cosine", m=32, ef_search=128),
    "compressed": IVFPQIndex(partitions=4096, subquantizers=32),
    "lexical": BM25Index(k1=1.2, b=0.75),
    "sparse": SparseVectorIndex(model="splade"),
    "late": LateInteractionIndex(candidate="muvera", rerank="maxsim"),
}

hybrid = HybridIndex(arms=[indexes["lexical"], indexes["dense"], indexes["late"]],
    fusion=ReciprocalRankFusion(k=60))

Rank fusion, graph recall, and diverse packing

MUVERAlexicalrecent
RRF
authorized nodesPageRankpassage projection
MMR
Context candidatesscores and contributions retained
compose_retrieval.py
from mari_components.retrieval import (
    maximal_marginal_relevance, personalized_pagerank,
    project_graph_scores, reciprocal_rank_fusion,
)

fused = reciprocal_rank_fusion(
    {"muvera": dense_ids, "lexical": lexical_ids, "recent": recent_ids},
    weights={"recent": 0.25}, rank_constant=60,
    eligible=authorized_document_ids.__contains__, limit=40)

nodes = personalized_pagerank(graph, query_seeds,
    allowed_node_ids=authorized_graph_nodes, damping=0.85)
passages = project_graph_scores(nodes.hits, node_passages, limit=20)

context = maximal_marginal_relevance(
    {hit.document_id: hit.score for hit in fused},
    similarity=passage_similarity, relevance_weight=0.65, limit=12)
assert nodes.converged

Memory segmentation and mutation plans

hybrid_topic_segments splits a stream only where an attention-boundary peak and a semantic-similarity valley agree. The application extracts candidates from those bounded groups and classifies each one as add, update, delete, or no-op. plan_memory_mutations validates the decisions without writing storage.

How it works

Normalize boundary and adjacent-similarity arrays to the n−1 gaps between n turns. A gap is eligible only when its attention score is a local peak above the configured boundary threshold and its adjacent semantic similarity is below the valley threshold. Eligible gaps split consecutive, non-overlapping segments. Mutation planning then requires exactly one decision per candidate, validates update/delete targets against current IDs, rejects duplicate adds and conflicting operations on one target, and returns a deterministic plan.

Turnsattention + similarity signals
topic boundary
Candidate memorieshost extraction and classification
validated plan
Host commitADD · UPDATE · DELETE · NOOP
memory_update.py
from mari_components.knowledge import (
    MemoryDecision, MemoryOperation, hybrid_topic_segments,
    plan_memory_mutations,
)

segments = hybrid_topic_segments(turns,
    attention_boundaries=attention, adjacent_similarities=similarity,
    similarity_threshold=0.40)

plan = plan_memory_mutations(existing, candidates, {
    "new-role": MemoryDecision(operation=MemoryOperation.UPDATE,
        target_id="role", reason="newer explicit statement"),
    "unchanged": MemoryDecision(operation=MemoryOperation.NOOP),
})
store.commit(plan, expected_generation=generation)
Research basis

Mem0: memory extraction and update operationsLightMem: topic-aware memory consolidation

The conjunctive peak/valley rule and mutation validation are Mari implementations; model-based classification remains outside the library.

Knowledge parsers

Models return JSON-like values. Parsers resolve all evidence against supplied document and section revisions and return immutable typed values. Research establishes each task formulation; Mari implements a deterministic validation boundary rather than the cited model.

How it works

Each parser first requires the recipe’s top-level collection, then validates every required field and enum, resolves evidence through the exact contract below, derives deterministic audit signals, and constructs frozen result types. It never repairs a claim’s meaning. Batch claim assessment is the exception to fail-fast parsing: rows are keyed back to caller order, absent rows become uncertain, and individually malformed rows do not erase valid siblings.

model proposalschemaexact evidencerevision bindingtyped candidate
ParserProducesResearch-backed taskAcademic sources
parse_factsFactCandidateAtomic claims and optional document-level relations with evidenceFActScore · DocRED
parse_claim_assessmentsFactAssessmentSupported, contradicted, or uncertain verdicts; decisive rows require evidenceFEVER
parse_decisionsDecisionCandidateDecision-related utterance extraction without treating topical language as proofHsueh & Moore · Karan et al.
parse_answerGroundedAnswerEvidence-selected document QA, citations, or explicit insufficient evidenceQASPER · ALCE
parse_answer_candidatesAnswerCandidate[]Reusable question-answer pairs bound to supporting passagesQASPER
parse_glossaryGlossaryCandidate[]Term-definition relations, aliases, and source spansDeftEval
parse_digestDigestSummaryOverall and topic summaries with separately inspectable evidenceQAGS · SummaC
parse_impactImpactAssessmentIn-scope affected-document proposals followed by deterministic dependency checksMari contract; no claimed benchmark reproduction
parse_refinementRefinementEdit[]Bounded, attribution-aware, fact-preserving edit proposalsRARR · FactEditor
answer.py
from mari_components.knowledge import parse_answer

raw = model(question, documents)
answer = parse_answer(question, documents, raw)
print(answer.disposition)         # grounded | insufficient_evidence
print(answer.grounding_coverage)  # deterministic text coverage
print(answer.evidence[0].quote)  # exact source text

Additional deterministic helpers include normalize_claim, deduplicate_fact_candidates, grounding_coverage, and excerpt. Recoverable batch drift is handled conservatively: assessment rows are restored to caller order, missing rows become uncertain, and good rows survive alongside invalid ones. Structured fact qualifiers preserve subject, relation, object, scope, validity, and conditions.

Evidence contracts

An evidence record is a byte-for-byte quotation bound to the exact document and section revision that was supplied to a parser. It is provenance, not a model confidence score.

How it works

  1. Restrict the corpus. Build an allowed map from only the KnowledgeDocument values passed by the caller. A model cannot cite an ID outside that map.
  2. Resolve the document. Require document_id. If exactly one allowed document contains the quote, Mari may recover a missing ID; zero or multiple holders is rejected.
  3. Match exact text. Require a non-empty quote and test literal containment in the canonical document body. Fuzzy, normalized, or semantic matches are not accepted.
  4. Resolve one section. Split the document into current sections and find sections containing the quote. A repeated quote spanning multiple sections is rejected unless section_id selects exactly one.
  5. Derive coordinates. Mari computes start = section.start + section.body.index(quote) and end = start + len(quote); it does not trust model-supplied offsets or revisions.
  6. Bind revisions. The accepted record receives the current document.revision, stable section_id, and content-derived section.revision. These become the invalidation key.
refunds.md · rev 8f31c2a

Enterprise refunds close after 30 days.

literal containment
+ unique section
Evidencedocument_id = …refunds.mdrevision = 8f31c2aquote = "30 days"start = 31 · end = 38section_id = enterprisesection_revision = sha256:…
evidence.py
from mari_components.knowledge import parse_facts

raw = {"facts": [{
    "claim": "Enterprise refunds close after 30 days.",
    "evidence": [{"document_id": doc.document_id,
                  "section_id": "enterprise",
                  "quote": "30 days"}],
}]}
fact = parse_facts([doc], raw)[0]
e = fact.evidence[0]
assert doc.body[e.start:e.end] == e.quote

# Rejected: unknown document, absent quote, or a repeated quote
# whose section cannot be selected unambiguously.

Dependency conversion

evidence_dependencies projects each record to (document_id, document_revision, section_id, section_revision), deduplicated by (document_id, section_id) and returned in stable order. Two records naming different revisions of the same key raise ValueError; silently choosing one would make reuse nondeterministic.

Research and standards

ALCE: citation correctness and completenessQASPER: evidence-bearing document QAFActScore: atomic factual claimsFEVER: evidence-backed verdictsW3C PROV: quotation, derivation, and revision

These works motivate inspectable evidence and revision provenance. Literal substring validation, unique-section resolution, and failure behavior are Mari engineering contracts.

Freshness and impact

Freshness is an exact dependency comparison. It answers “did an input revision change?”—not “is the answer still semantically correct?”

How it works

  1. Record dependencies. Every derived artifact stores the document or section revision used to build it.
  2. Select comparison granularity. If a dependency names a section and the caller supplies a section-revision map, compare section hashes. Otherwise compare the containing document revision as a conservative fallback.
  3. Classify every key. Missing document/section → missing; empty expected/current revision → unversioned; unequal revisions → stale; otherwise → current.
  4. Reduce deterministically. Overall precedence is missing > unversioned > stale > current. Changes and IDs are sorted, so the same inputs produce the same report.
  5. Propagate impact. impacted_artifacts evaluates each artifact independently and returns only non-current artifacts. Mari reports the set; the application chooses whether to regenerate, review, or retire them.
Policy answerdepends on § window
§ window30 → 45 days
Refresh queueonly affected artifacts
1 · missingsource or section absent2 · unversionedcannot compare safely3 · stalerevision differs4 · currentall revisions equal
freshness.py
from mari_components.knowledge import (
    FreshnessStatus, assess_dependencies, assess_freshness,
    impacted_artifacts,
)

report = assess_freshness(answer.evidence, current_revisions,
    current_section_revisions=current_sections)
if not report.reusable:
    refresh(report.changes, report.missing_dependency_ids)

stale = impacted_artifacts(dependencies_by_artifact, current_revisions,
    current_section_revisions=current_sections)

Document edit versus affected section

granularity.py
# The document changed v1 → v2, but the cited section is still s1.
current_revisions = {doc_id: "v2"}
current_sections = {(doc_id, "refund-window"): "s1"}

fine = assess_dependencies(deps, current_revisions,
    current_section_revisions=current_sections)
assert fine.status == FreshnessStatus.CURRENT

coarse = assess_dependencies(deps, current_revisions)
assert coarse.status == FreshnessStatus.STALE  # safe fallback
Research and standards

Build Systems à la Carte: dependency-driven recomputationRAG: updateable non-parametric knowledge and provenanceW3C PROV: revision and derivation

Mari applies build-system invalidation to knowledge artifacts. Status precedence, section fallback, and reuse policy are explicit Mari contracts, not semantic change detection.

Sections and incremental fact scans

document_sections maps Markdown headings to stable section IDs and content revisions. section_revisions builds the current revision map. Fact scans can then skip unchanged sections.

How it works

Scan Markdown heading lines, treating content before the first heading as a preamble. Normalize each heading into a slug and suffix collisions deterministically. Store absolute body offsets and hash the section body into its revision. pending_fact_sections compares (document_id, section_id) → revision with the last committed scan and yields new or changed sections only. Persist new scan revisions only after extracted facts commit, or a failed run would incorrectly suppress retry.

fact_scan.py
from mari_components.knowledge import (
    document_sections, fact_scan_revisions, pending_fact_sections,
)

sections = document_sections(document)
pending = pending_fact_sections([document], previous_scan_revisions)
facts = [parse_facts([document], model(section.body)) for section in pending]
next_revisions = fact_scan_revisions(pending)  # persist only after facts commit
Research and standards

Build Systems à la Carte: change detection and recomputationRFC 6920: digest-based content identity

Markdown heading segmentation and slug collision rules are Mari engineering contracts.

Tags and links

Managed tags

TagDefinition, TagAssignments, assign_tags, normalize_tag, and search_weight keep curation separate from provider-owned documents, so resync does not erase it.

Derived links

extract_explicit_links finds explicit references. derive_links adds bounded similarity links and produces typed LinkCandidate values.

How it works

Tag keys are normalized before add/remove set operations; definitions validate that assignments refer to known tags. Search weight combines assigned tag weights through deterministic policy rather than rewriting source relevance. Explicit-link extraction recognizes source references first. Similarity linking scores only caller-supplied candidate IDs, removes self-links, applies a threshold and limit, and sorts ties stably. Returned links are proposals; committing and interpreting them remains application policy.

curation.py
from mari_components.knowledge import (
    TagAssignments, TagDefinition, assign_tags, derive_links, search_weight,
)

definitions = {"canonical": TagDefinition(key="canonical", label="Canonical",
    kind="canonical", search_weight=2.0, behaviors=("Wins conflicts",))}
assignments = assign_tags(TagAssignments(), doc.document_id, definitions,
    add=("canonical",))
weight = search_weight(doc.document_id, assignments, definitions)
links = derive_links(doc.document_id, candidate_ids,
    score=lambda source, target: similarity_scores[source, target])
Research basis

Similarity measures for text processingA-MEM: dynamic linked-note organization

Mari’s managed-tag overlay and bounded link proposal rules are deterministic curation contracts.

Reviewed workflows and cached answers

Reviewed workflow indexes match new requests to approved intents. Policy thresholds independently control speculative retrieval and direct cached-response reuse.

How it works

Build an index from reviewed workflow intent vectors. At query time, compute normalized similarity, retain only workflows whose dependencies are authorized, and choose the best match with stable ties. Crossing the lower threshold may start retrieval speculatively; crossing the higher threshold only makes reuse eligible. A cached response is returned only after its exact evidence dependencies pass freshness checks. Similarity never overrides ACL or revision failure.

0.00run normally
0.72start retrieval
0.95consider reuse
1.00
workflow.py
from mari_components.trajectories import (
    WorkflowPolicy, build_reviewed_workflow_index, decide_reviewed_workflow,
)

index = build_reviewed_workflow_index(reviewed_workflows)
decision = decide_reviewed_workflow(query_vectors, index, current_revisions,
    policy=WorkflowPolicy(speculation_threshold=0.72, cache_threshold=0.95),
    allowed_document_ids=authorized_document_ids)

Related APIs: match_reviewed_workflow, start_speculative_retrieval, match_cached_response, and workflow_freshness. Reuse requires a strong match plus fresh, authorized dependencies.

Research basis

GPTCache: semantic caching for language-model queriesBuild Systems à la Carte: dependency-valid reuse

The two thresholds, authorization gate, and exact freshness condition are Mari policy.

Trajectories and agent evaluation

normalize_steps converts runtime records into privacy-bounded TrajectoryStep values. parse_trajectory_analysis validates model-proposed phases. Mari provides adapters, not an agent loop.

How it works

Adapters map framework events into ordered AgentEvent values. Normalization assigns stable step positions, keeps allowlisted metadata, and redacts sensitive argument names and transport fields. Tool evaluation compares observed names and counts against expectations; outcome evaluation compares terminal paths and completion. A proposed phase analysis must cover every observed event exactly once with contiguous, non-overlapping ranges and known tool families.

inspectsearch_knowledge
reason2 docs · 2 citations
answeroutcome: resolved
agents.py
from mari_components.agents import evaluate_outcome, evaluate_tools
from mari_components.trajectories import normalize_steps

steps = normalize_steps(runtime_events)
tools = evaluate_tools(events, expected_tools=("search_knowledge",))
outcome = evaluate_outcome(paths=("resolved",),
    expected_paths=("resolved",), completed=True)

AgentEvent and EventKind are framework-neutral. Optional adapters cover OpenAI Agents and LangChain/LangGraph. Normalization redacts common sensitive arguments; phase validation requires the returned ranges to cover observed events exactly.

trajectory_analysis.py
from mari_components.trajectories import parse_trajectory_analysis

analysis = parse_trajectory_analysis(normalized_events, model_labels,
    family_map={"search_product_knowledge": "inspect",
                "answer": "answer"})
Research and standards

AgentBench: multi-environment agent evaluationOpenTelemetry trace specification

Mari’s event schema, redaction list, exact phase coverage, and outcome predicates are library contracts.

Verification portfolios

Verification functions score already-parsed values and retain all successful attempts and failures for audit.

How it works

best_of_n calls the producer up to n times, parses each output, records parse failures without discarding successful siblings, scores valid candidates, and selects the highest score with stable first-wins ties; it may stop once the threshold is met. verdict_consensus counts typed verdicts rather than free text. Grounding scores combine declared deterministic components; they are used for ranking or abstention, never calibrated as probabilities.

verify.py
from mari_components.verification import best_of_n, score_grounded

result = best_of_n(
    lambda: model(question, documents),
    lambda raw: parse_answer(question, documents, raw),
    lambda answer: score_grounded(answer,
        required_ideas=("eligibility", "time limit")),
    attempts=3, threshold=0.90)

audit(result.selected, result.attempts, result.failures, result.stopped_early)
select_best

Scores existing candidates with stable tie-breaking.

verdict_consensus

Aggregates supported, contradicted, and uncertain assessments.

score_grounded

Evidence, coverage, completeness, corroboration, certainty.

harmonic_score
idea_completeness
Research basis

Self-consistency improves chain-of-thought reasoningFEVER: evidence-based verificationALCE: citation quality evaluation

Mari exposes an auditable selection portfolio; it does not reproduce model sampling or benchmark metrics.

Errors and deliberate boundaries

How it works

Exceptions classify which boundary failed and whether repeating the same request can help. Connector adapters translate provider responses into authentication, transient, or permanent failures. Snapshot validation raises IncompleteSnapshot before absence can become deletion. Knowledge parsers raise MalformedModelOutput before an invalid value crosses into typed state. Mari never retries automatically because retry budgets, clocks, credentials, and side effects belong to the host.

ErrorMeaningTypical handling
AuthenticationFailureCredentials rejectedRequest new credentials
TransientFailureTemporary provider failureRetry using app policy
PermanentFailureRequest cannot succeed unchangedRequire intervention
IncompleteSnapshotListing is not authoritativeDo not infer deletion
MalformedModelOutputGenerated value violates parser contractRetry or abstain

Safe representations and connector contracts

Credentials are excluded from connector configuration representations. HttpRequest representations redact authorization headers, bodies, URL userinfo, and common sensitive query parameters. check_connector_contract provides an executable contract check for third-party connector implementations.

connector_test.py
from mari_components import SyncMode
from mari_components.testing import check_connector_contract

pages = tuple(my_connector(config, request, http=fake_http))
report = check_connector_contract(pages, mode=SyncMode.FULL,
    starting_cursor=request.cursor)
assert report.pages == len(pages)

Not included: model client, prompt framework, database, scheduler, credential store, authorization engine, agent runtime, or worker queue.

Research-backed components and further designEach section labels current implementation separately from proposed interfaces

Hypothetical and hierarchical retrieval

These functions construct alternative query representations and bounded navigation structures. Generation, encoding, clustering, summarization, and relevance models are injected; Mari owns shape validation, deterministic IDs, budgets, and traces.

How it works

hypothetical_document_embedding weights and averages caller-encoded hypothetical answers, then L2-normalizes the vector used for retrieval; generated text is never stored as fact. build_summary_tree repeatedly validates a caller-proposed partition of every current root, creates stable parent nodes, and stops when the root count no longer decreases. walk_summary_tree expands the highest-scoring children under explicit branch and visit budgets and returns visited paths plus exhaustion state.

Generatehypothetical answer
Encodenormalized query vector
Retrievecandidate sections
Organizerecursive clusters
Walkbranch + visit budget

Paper-derived retrieval construction

hyde_raptor_memwalker.py · current
from mari_components.retrieval import (
    build_summary_tree, hypothetical_document_embedding, walk_summary_tree,
)

hyde_vector = hypothetical_document_embedding([
    document_encoder(text) for text in generate_hypotheses(query)
])

tree = build_summary_tree(section_text_by_id,
    cluster=lambda nodes, level: cluster_embeddings(nodes, level),
    summarize=lambda children, level: summarize(children, level))
walk = walk_summary_tree(tree, lambda node: similarity(query, node.text),
    branch_factor=2, max_visits=24)
sections = document_store.get_many(walk.leaf_ids)

Adaptive retrieval and compression

Retrieval can be triggered, corrected, rescored, or compressed at explicit decision points instead of running as one opaque model call.

How it works

CRAG routing maps evaluator scores through two thresholds to use the corpus, augment it with external search, or replace it. FLARE finds low-confidence tokens in a predicted future sentence, removes those tokens, and uses the remaining text as a retrieval query before regeneration. Self-RAG combines generation, retrieval, relevance, support, and utility signals with visible weights. RECOMP selects scored sentences under a token budget, then restores their source order.

adaptive_retrieval.py · current
from mari_components.retrieval import (
    CompressionSentence, plan_active_retrieval, plan_corrective_retrieval,
    selective_compression,
)
from mari_components.verification import score_self_rag_candidate

correction = plan_corrective_retrieval(retrieval_evaluator(query, hits),
    lower_threshold=-0.8, upper_threshold=0.6)
active = plan_active_retrieval(future.tokens, future.probabilities, threshold=0.2)
reflection = score_self_rag_candidate(generation_probability=signals.generation,
    retrieve_probability=signals.retrieve, relevance_probability=signals.relevant,
    support_probability=signals.supported, utility=signals.utility)

compressed = selective_compression([
    CompressionSentence(sentence_id=s.id, text=s.text, token_count=count_tokens(s.text),
        relevance=compressor.score(query, s.text)) for s in sentences
], token_budget=600, relevance_threshold=0.4)

Memory organization and evidence notes

These functions link related notes, rank memories for recall, and decide whether retrieved evidence can support an answer.

How it works

Note evolution applies a link threshold and a stricter metadata-evolution threshold to caller-supplied similarities. Salience exponentially decays recency, min-max normalizes recency, importance, and relevance over the candidate set, then returns every weighted contribution. Evidence-note decisions validate per-document relevance and answer support before choosing retrieved evidence, explicitly allowed parametric knowledge, or unknown.

memory_evidence.py · current
from mari_components.knowledge import (
    MemorySignal, plan_note_evolution, rank_salient_memories,
)
from mari_components.verification import (
    EvidenceNote, decide_from_evidence_notes,
)

evolution = plan_note_evolution(new_note.id, similarity_by_note_id,
    link_threshold=0.72, evolution_threshold=0.91)
salient = rank_salient_memories([
    MemorySignal(memory_id=m.id, hours_since_access=hours_since(m.last_accessed),
        importance=importance(m), relevance=relevance(query, m)) for m in memories
], recency_decay=0.995, limit=20)
decision = decide_from_evidence_notes([
    EvidenceNote(document_id=n.document_id, relevant=n.relevant,
        supports_answer=n.supports_answer) for n in model_notes
])

Knowledge admission and mutation planning

Admission is evaluated before reconciliation. A candidate may be valid JSON and still be unsafe, low-authority, redundant, or unsupported. Reconciliation runs only for accepted candidates.

How it works

Run provenance, evidence-span, recalled-input, secret, external-instruction, authority, and confidence rules over the candidate. Aggregate rule results into ACCEPT, DEFER, REJECT, or QUARANTINE with reason codes. Only accepted candidates reach mutation reconciliation, which validates add, merge, supersede, retract, or unchanged operations against the current canonical slot without writing storage.

Papers and standards

Indirect prompt injectionW3C PROVMem0: memory mutation operations

Disposition precedence and commit boundaries are proposed Mari contracts.
proposed / write_plan.py
candidate = extractor.propose(observation)
admission = admit(candidate,
    rules=[RequireEvidenceSpan(), RejectRecalledInput(), QuarantineSecrets(),
           QuarantineExternalInstructions(), EnforceSourceAuthority()],
    thresholds=AdmissionThresholds(accept=0.90, defer=0.65))

match admission.disposition:
    case ACCEPT:
        mutation = reconcile(candidate, current=artifact_store.canonical_slot(candidate))
        # ADD | MERGE | SUPERSEDE | RETRACT | UNCHANGED
    case DEFER: review_queue.put(candidate, admission.reasons)
    case QUARANTINE: quarantine.put(candidate, admission.reasons)
    case REJECT: audit.record(admission)

Entity resolution with explicit uncertainty

The cascade spends expensive work only after cheap deterministic checks. It never converts an ambiguous candidate into a merge without a configured threshold or review decision.

How it works

Block candidates by tenant, scope, and entity type; compare normalized exact aliases; calculate field-agreement and fuzzy scores; retrieve a small embedding neighborhood only for unresolved candidates; then apply separate link and review thresholds. Scores above link become a proposed canonical ID, scores in the review band retain all candidates and their feature trace, and lower scores remain distinct entities.

scope + type blocknormalized exactfield/fuzzy scoreembedding candidateslink · reject · review
proposed / resolve.py
resolver = EntityResolver([
    ScopeAndTypeBlock(), NormalizedAliasMatch(),
    ProbabilisticFieldMatch(link=0.95, review=0.72),
    EmbeddingCandidates(index=entity_index, limit=10),
])
resolution = resolver.resolve(candidate, scope=artifact.scope)
if resolution.ambiguous:
    review_queue.put(resolution.candidates, resolution.comparison_trace)

Graph recall and corpus aggregation

Passage retrieval and corpus summarization are different operations. Personalized PageRank is a current bounded multi-hop recall function. Leiden communities and map-reduce reports are proposed, separately versioned aggregation stages.

How it works

Link query mentions to authorized seed nodes, induce an allowed subgraph, and propagate Personalized PageRank mass until tolerance or iteration limits; project node mass back to evidence-bearing sections. Separately, Leiden partitions the graph into well-connected communities, recursive grouping forms levels, and evidence-linked community reports support global map-reduce queries. Local queries fan out from entities; drift queries start globally and open bounded local branches.

proposed / graph_algorithms.py
recall = PersonalizedPageRank(
    seeds=link_query(query, entities, facts), damping=0.50, hops=3,
    edge_filter=AuthorizedAt(scope=user.scope, at=query.time),
    project_to="source_sections")

communities = HierarchicalLeiden(resolution=1.0, max_size=40).fit(graph)
reports = summarize_communities(communities, evidence_policy=ExactEvidence())

answer = query_corpus(query, mode="global", reports=reports,
    reduction=RatedMapReduce(max_partial_answers=24))

Tiered memory consolidation

Tiers are policies over cost and lifecycle, not hard-coded stores. Topic segmentation is current; compression, promotion, and offline scheduling are proposed. Each promotion creates a dependency-bearing proposal, and raw observations remain available for audit.

How it works

Filter observations cheaply, group them at attention-peak/similarity-valley topic boundaries, compress within bounded groups, and score promotion from recurrence, recency, usefulness, and evidence diversity. Expensive resolving, superseding, and summarization run in an offline call/token budget. Promotion creates a new artifact revision linked to every contributing observation.

Observation buffercheap filters · content hashes
topic boundary
Session groupsbounded compression
offline window
Consolidated artifactsresolve · supersede · review
proposed / consolidation.py
policy = ConsolidationPolicy(
    segment=TopicBoundary(window=12, threshold=0.68),
    promote=PromotionScore(recurrence=0.30, recency=0.15,
        usefulness=0.35, evidence_diversity=0.20),
    schedule=OfflineWindow(max_model_calls=20, max_tokens=50000))
plan = plan_consolidation(observations, policy=policy)
commit(review(plan.mutations), dependencies=plan.dependencies)

Event sourcing and disposable projections

Canonical artifacts and append-only events remain authoritative. Search indexes, backlink tables, graph views, digests, and human-readable logs are projections with explicit build identities and safe swap semantics.

How it works

Append a validated event with an expected generation, fold ordered events through a deterministic projector into a staging version, and record schema plus embedding/configuration fingerprints. Validate counts, checksums, scope isolation, and sample queries before atomically switching the current pointer. A failed replay never replaces the last valid projection, and retaining the prior pointer makes rollback constant-time.

Canonical artifactsdocuments · events · reviews
deterministic fold
Staging projectionsvector · lexical · graph · Markdown
validate + swap
Current read versionrollback pointer retained
proposed / projections.py
events.append(KnowledgeEvent(kind="artifact.superseded", payload=mutation,
    actor=reviewer, expected_generation=41))

build = rebuild_projection(events, projector=SearchProjector(
    embedding_identity=embedder.fingerprint(), schema_version="3"))
validate(build, checks=[DocumentCount(), Checksums(), ScopeIsolation(), SampleQueries()])
projections.atomic_swap(build, retain_previous=True)

# A failed build never replaces the last valid read version.

Procedural learning and regression gates

Execution feedback can propose procedural updates, but promotion depends on held-out cases, negative outcomes, cross-procedure interference, and explicit review.

How it works

Reflect over a trajectory and observed outcome, turn the reflection into atomic add/update/tag/remove operations, and apply the patch to a copy of the active skillbook. Evaluate that candidate on its own cases, related-procedure cases, and known failures. Hard gates reject grounding or ACL regressions; passing creates a review proposal rather than activating it automatically. Worked, failed, and partial attempts remain separately retrievable.

proposed / skillbook.py
reflection = reflect(trajectory, outcome=outcome, evidence=observed_context)
patch = curate(reflection, operations={"ADD", "UPDATE", "TAG", "REMOVE"})
candidate = skillbook.apply_to_copy(patch)

gate = regression_gate(candidate, baseline=skillbook.active,
    suites=[own_cases, related_procedure_cases, known_failures],
    require={TaskSuccess(): NoRegression(), Groundedness(): AtLeast(0.95),
             ACLLeakage(): Exactly(0.0)})
if gate.passed:
	    skillbook.propose(candidate, trace=gate.trace)  # human promotion remains explicit

Long-horizon memory evaluation

A memory system needs separate measurements for writing, updating, retrieving, temporal reasoning, abstaining, and respecting context limits. One aggregate answer score hides which subsystem failed.

How it works

Freeze conversations, source revisions, expected evidence, and change events into cases. Replay each case under several corpus sizes and context budgets. Score extraction at write time, evidence recall at query time, cross-session synthesis, ordering and date reasoning, correction after source updates, abstention when evidence is absent, and ACL leakage. Store per-stage traces with every score so a regression points to the responsible parser, index, policy, or packing decision.

Extractionprecision · recall · evidence
Retrievalrecall@k · rank · authorization
Synthesissupport · completeness
Temporalorder · valid time · updates
Abstentionunsupported-answer rate
Operationstokens · latency · refresh work
proposed / memory_eval.py
report = evaluate_memory_system(system, cases,
    corpus_sizes=(100, 10_000, 1_000_000),
    context_budgets=(2_000, 8_000, 32_000),
    metrics=[ExtractionF1(), EvidenceRecall(k=10), UpdateFidelity(),
             TemporalAccuracy(), AbstentionPrecision(), ACLLeakage()])

report.by_capability["updates"]
report.failures  # case, stage, revisions, trace, observed output
Paper

LongMemEval: five long-term memory capabilities

The multi-scale replay matrix and ACL/update constraints are proposed Mari evaluation requirements.

Unified artifact model

A generic envelope would give facts, answers, decisions, summaries, procedures, and graph statements common identity, scope, provenance, review, temporal, and supersession semantics.

How it works

The payload type T holds domain content; the envelope holds governance. Artifact identity stays stable while each revision is immutable. Evidence and derived_from capture inputs, generated_by captures the producing activity/configuration, validity bounds describe when the claim applies, and supersedes closes a lineage edge without erasing history. Stores reject a revision if its evidence, scope, or predecessor is invalid.

KnowledgeArtifact[T]
identity + revisionKnowledgeScopeevidencevalid timereview stategeneratorsupersedes
proposed / artifacts.py
artifact = KnowledgeArtifact[PolicyFact](
    id="fact:refund-window:enterprise", revision="sha256:8f31…",
    value=PolicyFact(days=30),
    scope=KnowledgeScope(tenant="acme", space="support"),
    evidence=answer.evidence, valid_from="2026-01-01", valid_to=None,
    recorded_at=clock.now(), review_state=ReviewState.APPROVED,
    generated_by=Activity("refund-policy/v4", model="extractor@2026-08"),
    derived_from=("github:policy/refunds.md@8f31c2a",),
    supersedes=("fact:refund-window:enterprise@v2",))

Storage protocols and conformance

Capability protocols would allow independent document, artifact, vector, lexical, and graph implementations.

How it works

Protocols specify observable behavior rather than backend classes. A store implementation declares capabilities, then runs a shared conformance suite against replay, atomic revision, isolation, deletion, deterministic ordering, and point-in-time cases. Cross-store operations use an application transaction/outbox boundary; Mari does not pretend separate databases share an atomic commit. Indexes remain disposable projections that can be rebuilt from documents and artifacts.

proposed / stores.py
class DocumentStore(Protocol):
    def commit_sync(self, plan: SyncPlan) -> None: ...
    def get_many(self, ids: Iterable[str]) -> Sequence[KnowledgeDocument]: ...

class ArtifactStore(Protocol):
    def apply(self, mutation: ArtifactMutation) -> None: ...
    def at_time(self, id: str, when: datetime) -> KnowledgeArtifact | None: ...

class VectorIndex(Protocol): ...
class LexicalIndex(Protocol): ...
class GraphIndex(Protocol): ...

Conformance tests would cover replay safety, deterministic ordering, point-in-time reads, tenant isolation, atomic revisions, and delete behavior.

Typed knowledge pipelines

Composable stages would transform typed inputs and emit reviewable ArtifactMutation values: create, revise, supersede, retract, or leave unchanged.

How it works

Each stage declares input/output types, a versioned configuration fingerprint, and whether it is pure or calls an injected service. The runner topologically orders stages, passes immutable batches, records input revisions and stage results, and stops dependent stages after failure. Outputs are mutation proposals; a final policy validates evidence, scope, and expected artifact revision before the application commits them.

extractresolvelinkreviewindex
proposed / pipeline.py
pipeline = Pipeline[KnowledgeDocument, KnowledgeArtifact](
    extract(FactExtractor(model=model)), resolve(EntityResolver(catalog=entities)),
    link(EvidenceLinker()), review(ReviewPolicy(min_corroboration=2)),
    index(vector=vector_index, graph=graph_index))

result = pipeline.run(changed_documents)
artifact_store.apply(result.mutations)
trace_store.write(result.trace)

Retrieval plans and context envelopes

A retrieval plan would run explicit arms, fuse ranks, enforce scope and freshness, rerank, and pack a bounded context envelope. Its trace explains inclusion and exclusion.

How it works

Run semantic, lexical, graph, and recency arms over authorized IDs. Convert arm scores to ranks and combine them with reciprocal-rank fusion, then discard stale dependencies, rerank survivors, diversify near-duplicates, and greedily pack whole evidence excerpts under token/document limits. The envelope contains rendered context plus source revisions and per-candidate include/exclude reasons, allowing the caller to reproduce what the model saw.

semanticlexicalgraphrecent
RRF
authorizefreshnessrerank
budget
ContextEnvelopeexcerpts · evidence · revisions · trace
proposed / context.py
plan = RetrievalPlan(arms=[Semantic(vector_index, limit=40),
    Lexical(lexical_index, limit=30), GraphExpand(graph_index, hops=2),
    RecentChanges(window="14d")], fusion=ReciprocalRankFusion(k=60),
    reranker=ExactMaxSim())

context = assemble_context(query, plan=plan, scope=user.knowledge_scope,
    budget=ContextBudget(tokens=6000, documents=12))
model(context.render())
audit(context.retrieval_trace)

Bi-temporal knowledge graph

Statements would track valid time (when the claim applied) and transaction time (when the system learned it), supporting historical queries and late corrections.

How it works

An assertion is append-only and carries two intervals. A correction learned today may close an older assertion’s transaction interval while preserving its historical valid interval. Query at filters valid time; known_at filters transaction time; both must contain their requested timestamp. Contradictions create explicit edges or superseding revisions instead of destructive overwrites.

valid timeJan ───────── Aug
transaction timelearned Sep 01 ───▶
proposed / graph.py
graph.assert_fact(subject="plan:enterprise", predicate="refund_window_days",
    object=30, valid_time=Interval("2026-01-01", "2026-08-31"),
    transaction_time=clock.now(), evidence=evidence)

then = graph.query(at="2026-06-01", known_at="2026-09-01")
now = graph.query(at=clock.now(), known_at=clock.now())

Procedural knowledge

Successful trajectories could produce versioned procedure candidates. Regression gates and human review would separate observed behavior from active behavior.

How it works

Cluster successful traces by reviewed intent, extract a parameterized tool/action sequence with preconditions and failure exits, and retain links to the source traces. Replay the candidate on held-out cases, compare task success, tool correctness, grounding, cost, and regressions with the active version, then produce a review proposal. Only an explicit application commit can activate a version; failed attempts remain negative evidence.

trajectoriescandidateregression suitereviewactive version
proposed / procedures.py
candidate = learn_procedure(successful_runs, intent="process enterprise refund")
report = evaluate_procedure(candidate, cases=refund_regression_suite,
    metrics=[TaskSuccess(), ToolCorrectness(), Groundedness(), Cost()])
if report.passes_gates:
    procedures.propose(candidate, report=report)  # review still required

Evaluation and compilation

A compiler would search pipeline and retrieval configurations against knowledge-system objectives and return a reviewable, versioned configuration proposal.

How it works

Declare tunable parameters, hard constraints, and optimization metrics. For each candidate configuration, run the same frozen training cases, cache stage results by configuration/input fingerprints, reject any candidate that violates provenance, update fidelity, or ACL constraints, and rank feasible candidates on grounded recall, cost, and latency. Validate the selected configuration once on held-out cases; compilation returns a report and proposal, never a deployment side effect.

Grounded recallmaximize
Provenance accuracyrequire 1.0
Update fidelityrequire 1.0
ACL leakagerequire 0.0
Context tokensminimize
Latency p95minimize
proposed / compile.py
compiled = compile_knowledge_system(pipeline, trainset=train_cases,
    validation=validation_cases,  # optimizer may inspect these; never test_cases
    objectives={GroundedRecall(): Maximize(), ProvenanceAccuracy(): Require(1.0),
        UpdateFidelity(): Require(1.0), ACLLeakage(): Require(0.0),
        ContextTokens(): Minimize(), LatencyP95(): Minimize()},
    search_space=KnowledgeConfigSpace())

review(compiled.config, compiled.report, compiled.failures)
test_report = evaluate_once(compiled.config, cases=test_cases)
deploy(compiled.config, evidence=test_report)  # explicit application action
Copied