The KRI

A Key Risk Indicator has:

  • A slug, the stable contract between connector and KRI (e.g. critical_cves_unpatched_gt_30d).
  • A name and description for humans.
  • A source, the kri_source that writes values.
  • Thresholds (warn, critical) and a direction (higher-is-worse / lower-is-worse).
  • Links to one or more risks and a business outcome.

A KRI without links to risks and outcomes is valid but useless, it shows up on the dashboard but doesn’t roll up. The onboarding flow won’t let you finish until each KRI is wired.

The source

A kri_source is a per-tenant connection to an integration. It stores:

  • Source type + vendor ID, the pair that resolves to a connector.
  • API endpoint, the vendor URL (auto-filled for fixed-URL vendors).
  • Auth type and encrypted credentials.
  • Schedule, daily (default), hourly, or manual.
  • Extra config, non-secret JSON (e.g. {"customer_id":"abc"} for Google Workspace).

How the runner writes values

  1. The scheduler wakes up and resolves every source whose next-run time has passed.
  2. For each source, the dispatcher looks up the connector by vendor_id and calls run(ctx).
  3. The connector fetches data from the vendor, computes each KRI value, and runs UPDATE kri SET value = ?, updated_at = ? WHERE source_id = ? AND id = ?.
  4. If a KRI slug is missing, the row is counted as rowsSkipped, it means the tenant hasn’t wired that KRI yet. Not an error.
  5. The run row is written with rowsWritten, rowsSkipped, and a summary of items fetched.

Rollups

Dashboards compute three levels of rollup:

  • Per-KRI colour (green / amber / red) from its thresholds.
  • Per-risk severity from the KRIs and controls linked to that risk.
  • Per-outcome severity from the risks linked to the outcome.

See Platform overview for how KRIs, risks, controls, and outcomes relate.

Manual KRIs

Not every KRI needs an integration. For values that only a human knows (e.g. “has the quarterly board risk review happened?”), create the KRI without a source and edit its value by hand. The updated_at ages the same way as an automated value, so stale manual values show up in the Draxis staleness report.

AI Drop Zone

When a tool has no connector, the AI Drop Zone turns unstructured evidence into typed KRIs. Drag a PDF, paste a CSV, upload a log snapshot or screenshot, or POST to its webhook, and an AI extractor reads the artifact and proposes KRI values against the catalog allow-list. Pentest reports, vendor SOC 2s, audit notes, config exports, and screenshots all work.

Every extracted value cites the source span it came from, so you can trace a number back to the exact line of the report it was read from. High-confidence extractions auto-accept; the rest queue in the Inbox for an analyst to confirm. The Drop Zone is an AI proposal surface: values pass through the confidence-scored review pipeline rather than landing as ground truth. Full detail in the AI Drop Zone integration guide.

MCP server push

Any external scheduler or MCP-enabled AI client can push a KRI value straight into Draxis through the MCP server. This is the External Push path. Use it when you already have custom data-fetching logic, a Jira JQL counting tickets by age, a GitHub Actions build-failure rate, a Lambda that crunches a regional API, and you just want Draxis to record the resulting number. Unlike the Drop Zone, pushed values are ground truth: they bypass the AI proposal pipeline and write directly to the KRI.

An admin first provisions an external_push source from Settings → Integrations and mints a push token scoped to that one source. The scheduler then calls two source-scoped MCP tools:

  • create_external_push_kri, an idempotent create of a KRI under the source (name, measurement type, optional thresholds). Safe to call on every run.
  • push_kri_value, records an observation. In one transaction it recomputes the KRI’s status from its thresholds, sets the value and timestamp, marks the source live in dashboard rollups, and writes an audit row. An optional ISO-8601 timestamp does real historical backfill, so you can seed a trend chart or catch up after an outage.

The push token is restricted to a single kri_source.id and to those two tools. It cannot read your risk register, vendors, or any other KRI. One credential per job, blast radius bounded to one source. Full detail in the External Push integration guide.

API

  • GET /api/kri-sources, list sources.
  • PUT /api/kri-sources/<id>, create / update.
  • POST /api/kri-sources/<id>/test, probe connectivity.
  • POST /api/kri-sources/<id>/run, trigger a run now.
  • GET /api/kri-sources/<id>/runs, run history.
  • GET /api/kris, PUT /api/kris/<id>, KRI CRUD.
  • POST /api/mcp (JSON-RPC), the MCP server endpoint that exposes create_external_push_kri and push_kri_value for external push, plus submit_dropzone_artifact for Drop Zone uploads.