Core concepts
The five ideas behind SentnelOps, in the order you'll meet them. Everything else in these docs is detail on one of these.
Orgs and credentials
Your org is a hard tenancy boundary — every agent, policy, call log, and user belongs to exactly one org, and nothing crosses it (another tenant's resources 404 as if they don't exist). Two kinds of credentials act inside an org:
| Credential | Who uses it | Acts as |
|---|---|---|
snops_key_… | Machines: CI, scripts, the SDK | admin (full access) |
| Session JWT (12 h) | Humans, via login | their assigned role |
| Agent JWT | Agents, only at the proxy | the agent's identity — never a user |
The three are deliberately not interchangeable: an agent token is rejected everywhere except the proxy, and a user session is rejected at the proxy.
Agents are first-class identities
An agent record answers the questions security teams ask after an incident: who is this, who owns it, what may it touch, when does it expire, who approved it? Fields: name, owner, environment (dev | staging | production), risk level, allowed/denied MCP servers, lifecycle status, expiry, and review dates. Its JWT is self-contained — the proxy knows the caller without a callback.
Lifecycle, not a boolean
draft → approved → active ⇄ suspended → decommissioned (terminal)
Production agents cannot activate without approval, and the approver must be a different person than the creator (403 segregation_of_duties). Suspension freezes the agent's scope and requires a reason. Every transition is written to an append-only audit log.
Policy: two levels, one evaluator
Level one lives on the agent: allowed_mcp / denied_mcp — which servers it may reach at all. Level two lives in policy YAML — your org's own document, edited on the dashboard's Policy page and overlaying the platform default: per-server allow/deny tool lists with declared blast radius scores (0.0 read-only → 1.0 destructive). One pure function evaluates both levels everywhere it matters:
| Surface | What the same decision does |
|---|---|
POST /policy/check | Advisory — returns the decision, blocks nothing |
| Proxy in observe mode | Records it as would_block — still blocks nothing |
| Proxy in enforce mode | Acts on it — denied calls never reach the upstream |
Because it's literally the same code path, the would_block counts you accumulate in observe mode are an exact preview of enforcement — not an estimate.
The observe → enforce journey
This is the intended adoption path, one deliberate step at a time:
| Stage | What happens | Risk |
|---|---|---|
| 1. Observe (default) | Everything forwards; every call logged with would_block | Zero — the proxy fails open |
| 2. Review | Dashboards show which calls your policy would stop | Zero — you're reading a report |
| 3. Enforce staging | One YAML line: staging: enforce | Contained |
| 4. Enforce production | Same line for production; high-blast calls can require human approval | Known in advance from stage 2 |
Everything is evidence
The call log, audit trail, and registry all export as CSV (/mcp-calls/export.csv, /agents/export.csv, /reports/governance) — designed to be handed to auditors or streamed to a SIEM. The audit log is append-only at the database layer: there is no API, role, or SQL grant that rewrites history.