MIR participation

Turn your Volt app into a Memory Infrastructure Registry partner. Your app becomes a market; its users become participants whose actions build a portable, cross-partner reputation. You record what users do, and you can resolve a participant's neutral signals (tier, history, claim status) — reputation that follows them across every MIR partner, not just your site.

Enable it in the wizard (npm run dev -- --editFeatures → mir), or add mir to VOLT_ADDONS.

The onboarding flow

MIR only meters events for a public, domain-verified partner, so the config only offers MIR once SITE_URL is a real routable domain — a localhost install can never pass domain verification, so it isn't offered the option. Onboarding is three steps:

  1. Register — in the config's MIR participation section, click Register with MIR. You get a sandbox partner, an API key, and a domain-challenge token, written to .env on Apply.
  2. Deploy — ship your site. The add-on serves the challenge token at /.well-known/mir-challenge, so MIR can confirm you control the domain.
  3. Promote — back in the config, click Promote to production. MIR fetches your challenge, verifies the domain, and swaps your sandbox key for a production key.

Sandbox history doesn't carry over — real participation starts at zero on promote. In sandbox, submit → resolve is immediate; in production, a resolve is provisional until the participant links their own MIR account.

Recording participation

The add-on exposes a client on app.locals.mir (reach it in any route via req.app.locals.mir):

// record an event — eventType is a locked dotted enum (e.g. "transaction.completed")
await req.app.locals.mir.submitEvent(user.id, "transaction.completed");

// resolve a participant's neutral signals
const r = await req.app.locals.mir.resolveUser(user.id);
if (r.found)            { /* r.signals — tier, event counts, recency, claim status */ }
else if (r.provisional) { /* production: events exist, user hasn't linked MIR yet */ }
else if (r.unknown)     { /* no events for this user */ }

userExternalId (the first argument) is your app's user id — MIR maps it to a participant under your partner. weight defaults to 1 (use claims for negative signals). Events carry only four fields (userExternalId, eventType, weight, occurredAt) — no PII, by design.

Emission is opt-in

Being a registered partner does not mean events flow. Sending data about your users to an external registry is a deliberate choice, so submitEvent is a no-op until you opt in — tick Emit participation events in the config (MIR_EMIT=on). Off, submitEvent returns { skipped: true } and nothing leaves your app; resolveUser (a read) still works. This separates becoming a partner from contributing events — flip emission on only when you're ready.

Environment

Var What
MIR_API_KEY Your partner key (mir_sandbox_…, or production mir_…).
MIR_CHALLENGE The domain-verification token, served at /.well-known/mir-challenge.
MIR_EMAIL Partner contact email (required to register).
MIR_PARTNER_ID / MIR_ENV Your partner id + sandbox/production.
MIR_BASE_URL Override the API base (default https://mirregistry.org/v1).

The wizard writes all of these for you — you rarely touch them by hand.