Authority governance engine for autonomous decisions.
MIDAS determines whether an automated agent is within authority to perform a consequential action. Every evaluation produces exactly one outcome and one tamper-evident audit envelope — capturing what was requested, what authority was resolved, and why the outcome was reached.
An interactive developer sandbox is available at:
http://localhost:8080/explorer
Open it in a browser. Demo scenarios (accept, escalate, reject, request clarification) are pre-loaded and ready to run. Sign in with demo / demo in default mode. Explorer runs on an isolated in-memory store — requests sent through it never touch the configured backend. It is a developer tool only — do not expose it in production.
docker compose up --buildThen open http://localhost:8080/explorer and sign in with demo / demo.
No database required. MIDAS starts with an in-memory store and demo data pre-loaded.
Run without demo mode:
Bash/sh:
MIDAS_DEV_SEED_DEMO_DATA=false MIDAS_DEV_SEED_DEMO_USER=false docker compose up --buildPowerShell:
$env:MIDAS_DEV_SEED_DEMO_DATA="false"; $env:MIDAS_DEV_SEED_DEMO_USER="false"; docker compose up --buildThese variables persist for the current shell session. Open a fresh shell (or unset the variables) to return to default demo behaviour.
Run with Postgres: uncomment the postgres service and environment block in docker-compose.yml.
go run ./cmd/midasThen open http://localhost:8080/explorer and sign in with demo / demo.
⚠️ Auth mode defaults toopenfor local development. Before exposing MIDAS to a network, setMIDAS_AUTH_MODE=requiredand configureMIDAS_AUTH_TOKENS. See Authentication.
MIDAS supports two evaluation modes. Choose evaluation mode based on your governance requirements.
Inferred mode — no setup required. Enable inference and evaluate immediately. MIDAS creates the structural entities (capability, process, surface) automatically on first call.
# Enable inference (Postgres required)
export MIDAS_INFERENCE_ENABLED=true
curl -s -X POST http://localhost:8080/v1/evaluate \
-H "Content-Type: application/json" \
-d '{
"surface_id": "loan.approve",
"agent_id": "agent-credit-001",
"confidence": 0.91,
"request_id": "req-demo-001",
"request_source": "lending-service"
}' | jq .Expected response (inference creates structure on first call):
{
"outcome": "accept",
"reason": "WITHIN_AUTHORITY",
"envelope_id": "...",
"inference": {
"capability_id": "auto:loan",
"process_id": "auto:loan.approve",
"surface_id": "loan.approve",
"capability_created": true,
"process_created": true,
"surface_created": true
}
}Explicit mode — requires pre-created structure (via control plane apply). Provides strict governance validation: process_id must exist and must belong to the given surface_id. This is the default and is recommended for production.
curl -s -X POST http://localhost:8080/v1/evaluate \
-H "Content-Type: application/json" \
-d '{
"surface_id": "surf-loan-auto-approval",
"process_id": "proc-loan-standard",
"agent_id": "agent-credit-001",
"confidence": 0.91,
"consequence": {"type": "monetary", "amount": 4500, "currency": "GBP"},
"context": {"customer_id": "C-8821", "risk_band": "low"},
"request_id": "req-demo-001",
"request_source": "lending-service"
}' | jq .Retrieve the full governance record:
curl http://localhost:8080/v1/decisions/request/req-demo-001?source=lending-service | jq .Authority flows in one direction:
DecisionSurface → AuthorityProfile → AuthorityGrant → Agent
Surface — what is governed (a business decision boundary). Carries name, domain, owner, required context keys. Does not carry thresholds.
Profile — how much authority is permitted on a surface. Carries confidence threshold, consequence limit, escalation mode, policy reference.
Grant — thin link from an agent to a profile. No governance semantics of its own.
Agent — any autonomous actor: AI model, automated service, or human operator.
See docs/core/authority-model.md.
Every evaluation is atomic, deterministic, and produces a tamper-evident audit chain. The envelope — outcome, authority evidence, audit events — is written in a single database transaction. Either everything commits or nothing does.
Audit events are hash-chained in sequence. Each event's SHA-256 hash is derived from the previous event's hash. The final event hash is anchored in the envelope's Integrity section. If any event is modified, deleted, or inserted after the fact, the chain breaks at that point.
Verification requires only the stored event hashes and the anchored final hash on the envelope — not access to application secrets. See docs/core/envelope-integrity.md.
| Variable | Default | Description |
|---|---|---|
MIDAS_STORE_BACKEND |
memory |
memory or postgres |
MIDAS_DATABASE_URL |
(none) | PostgreSQL connection string. Required when MIDAS_STORE_BACKEND=postgres. |
The schema is applied automatically at startup (internal/store/postgres/schema.sql). No separate migration step is needed.
| Variable | Default | Description |
|---|---|---|
MIDAS_AUTH_MODE |
open |
open (no auth, dev only) or required (bearer token enforced). |
MIDAS_AUTH_TOKENS |
(none) | Semicolon-separated entries: token|principal-id|role1,role2. Required when MIDAS_AUTH_MODE=required. |
Generate tokens with openssl rand -base64 32, then:
export MIDAS_AUTH_TOKENS="<token>|svc:deploy|platform.operator;<token2>|user:alice|platform.admin,governance.approver"Roles: platform.admin, platform.operator, platform.viewer, governance.approver, governance.reviewer.
MIDAS_AUTH_MODE |
MIDAS_AUTH_TOKENS |
Result |
|---|---|---|
required |
Set | Bearer token auth enforced |
required |
Unset | Fatal — no tokens configured |
open |
— | No auth — UNSAFE FOR PRODUCTION logged |
| Variable | Default | Description |
|---|---|---|
MIDAS_INFERENCE_ENABLED |
false |
true enables automatic structure inference on POST /v1/evaluate. Requires Postgres. |
When false (the default), process_id is required on every evaluate call. When true, omitting process_id causes MIDAS to infer and create the structural entities automatically.
| Variable | Default | Description |
|---|---|---|
MIDAS_LOG_LEVEL |
info |
info or debug |
MIDAS_EXPLORER_ENABLED |
(auto) | true enables Explorer UI. Auto-enabled in memory mode. |
MIDAS_DISPATCHER_ENABLED |
false |
true starts the Kafka outbox dispatcher |
MIDAS_KAFKA_BROKERS |
(none) | Comma-separated host:port. Required when dispatcher enabled. |
Full variable reference: docs/operations/deployment.md.
| Document | Contents |
|---|---|
| docs/getting-started.md | Prerequisites, quickstart, first evaluation walkthrough |
| docs/explorer.md | Explorer sandbox: usage, endpoints, auth, envelope inspector |
| docs/control-plane.md | Apply, plan, surface lifecycle, versioning |
| docs/core/authority-model.md | Surfaces, profiles, grants, the authority chain |
| docs/core/runtime-evaluation.md | Evaluate endpoint, outcomes, idempotency, audit |
| docs/core/envelope-integrity.md | Envelope structure, hash chain, integrity verification |
| docs/core/data-model.md | PostgreSQL schema reference |
| docs/guides/lifecycle-management.md | Inferred structure lifecycle: promote and cleanup |
| docs/guides/authentication.md | Local IAM, OIDC/SSO, and API bearer token authentication |
| docs/guides/rego-policies.md | Policy behavior: NoOp default and future direction |
| docs/operations/deployment.md | Surface lifecycle: apply → approve → active → deprecated |
| docs/operations/escalations.md | Escalation outcomes, listing and resolving |
| docs/operations/events.md | Outbox, dispatcher, Kafka, event contracts |
| docs/operations/integrations.md | Kafka integration, SSO/OIDC |
| docs/api/http-api.md | Complete HTTP API reference |
| docs/architecture/architecture.md | Deep architecture overview |
Apache License 2.0