SentnelOpsSentnelOpsbeta
LAYER 2 · LIFECYCLE & POLICY

Lifecycle & policy reference

Every lifecycle endpoint with its role gate and exact error codes, the full policy YAML schema, the review cadences, and the advisory /policy/check contract.

Lifecycle endpoints

All under Authorization: Bearer (session JWT or org API key). Error bodies carry {"code", "detail"}; any transition on a decommissioned agent returns 409 terminal_state.

Method / pathMin roleRulesErrors
POST /agents/:id/approvesecuritydraft → approved, or re-approval of a suspension over 30 days old. Body: {approved_by, note?}.403 segregation_of_duties (approver = creator), 409 illegal_transition (wrong state, or suspension still under 30 days — use reactivate)
POST /agents/:id/activatedeveloperapproved → active. Body: {actor}.409 approval_required (from draft), 409 illegal_transition
POST /agents/:id/suspendsecurityactive → suspended. Body: {actor, reason}; reason must be non-empty. Scope edits are refused until reactivation.400 reason_required, 409 illegal_transition; later scope edits: 409 scope_frozen on PATCH /agents/:id
POST /agents/:id/reactivatesecuritysuspended → active, only while the suspension is under 30 days old. Body: {actor}.409 reapproval_required (over 30 days), 409 illegal_transition
DELETE /agents/:id?actor=securityAny state → decommissioned. Terminal: revokes all active tokens and audits a final snapshot of the agent row.409 terminal_state (already decommissioned)
POST /agents/:id/reviewsecurityNot a transition. Sets last_review = now, advances next_review by the risk cadence. Body: {actor}.409 terminal_state

Initial status at registration: productiondraft; dev and stagingactive. Registration itself is a layer 1 concern.

Policy YAML schema

KeyTypeDefaultMeaning
policies.defaults.deny_unlistedbooltrueA tool in neither allow nor deny is denied. Switch off to allow unlisted tools (decisions then say allow_unlisted).
policies.defaults.high_risk_requires_reviewbooltrueFlags high-risk agents for mandatory review in governance reporting.
policies.<agent>mapOne block per agent, keyed by agent id or name (id matched first). No block = the agent keeps its server-level decision only.
policies.<agent>.<server>mapRules for one MCP server. Only allow, deny, and blast_radius are accepted — any other key fails validation at load.
…<server>.allowlist[str][]Tool names permitted on this server.
…<server>.denylist[str][]Tool names denied on this server. Deny beats allow.
…<server>.blast_radiusmap[str, 0–1]{}Declared severity per tool. Logged with every call; drives layer 4's approval threshold.

Where the YAML lives: your org's own document, edited on the Policy page or via GET/PUT/DELETE /policy/source (write access needs the security role; saves are strictly validated and live within ~5 seconds; delete reverts to the platform default). The platform default itself is files on disk: every *.yaml/*.yml in the policies directory, merged in filename order (later wins), hot-reloaded on mtime change, strictly validated at load. The optional top-level enforcement: section belongs to layer 4 and is documented with the gateway and enforcement — absent, everything observes.

Review cadence

Risk levelCadenceSweep behavior
high30 daysnext_review initialised from last_review (or created_at) + 30d where missing
medium90 daysOverdue agents get one review_overdue audit event per missed deadline
low180 daysAgents past expires_at get one expired audit event per expiry; decommissioned agents are skipped

POST /policy/check

Advisory evaluation of the exact logic the gateway runs — min role viewer, enforces nothing, and every check writes a policy_checked audit event. Omit tool for a server-level decision.

Request
{
  "agent_id": "AGENT_ID",          // required — must belong to your org (else 404)
  "mcp_server": "github-mcp",      // required
  "tool": "delete_repo"            // optional — tool-level decision from the YAML store
}
Response
{
  "permitted": false,
  "reason": "tool delete_repo is denied on github-mcp",
  "agent_id": "AGENT_ID",
  "policy_rule": "github-mcp.deny"   // the winning rule; null on status denials
}

policy_rule is one of: denied_mcp, default_deny, allowed_mcp, <server>.deny, <server>.allow, deny_unlisted, allow_unlisted — or null when the denial came from the agent's lifecycle status.