Files
oikos/api/openapi.yaml
dtoro ad29295c93
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled
feat(web): make the entity window a triage surface, not a data dump
The window rendered the same 13 collapsible sections for every entity, sorted
only by "does it have content". Audit trail carried the same visual weight as
Health, and the window answered "what data do we hold about X?" rather than
"what do I need to know, and what should I do?".

Measured against prod: host:hubris has 223 relations, 1,601 events, 2.7M metric
samples and 148 executions; an ingress route has three facts. Both got 13
identical headers. Expanding a host put ~540 interactive elements on screen.

- **A verdict header that never collapses.** Not just "down" but *why*:
  "ping failing · 5 of 6 checks passing". That line did not previously exist
  and could not have — checks rendered as configuration, never as results.
- **Sections composed per type.** A document has no checks, metrics or blast
  radius; a signal or execution is a record, not a thing. Infrastructure gets
  Status/Impact/Activity/Metrics/Reference, knowledge types lead with Content,
  records get a minimal view. Unknown types fall back to infrastructure so a
  new entity type is never a blank window.
- **Status replaces Monitoring**, showing each check's own verdict and when it
  last ran — the section that answers the header's "why".
- **Impact** finally calls /entities/{id}/blast-radius. The endpoint has existed
  since the first API and had no frontend caller anywhere, despite
  .agents/OIKOS.md naming blast radius as the reason the ontology exists. Its
  outgoing-edges-only limitation is stated in the UI rather than hidden.
- **Activity merges four lists** (executions, signals, events, agent activity)
  that were telling one story in four places.
- **Relations cap at 8 with a drill-in** — 540 interactive elements down to 126.
- **Ask Nomos** opens a task pre-scoped to what you are looking at, seeded with
  the verdict just computed, via an optional draft threaded through
  openNewTaskWindow -> NewTaskChat -> ChatThread.

Requires exposing check_defs.last_health/last_run_at through the API (the
columns landed with the health-aggregation work but were never surfaced).
Adding a fourth enum containing "unknown" made oapi-codegen disambiguate all
enum constants by type prefix, so metrics.go moves to gen.TrendDirection*.

Verdict derivation and type->section composition live in $lib/entityView.ts as
pure functions with 15 unit tests, including the host:strong case that
motivated this.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-29 09:24:28 +02:00

3321 lines
82 KiB
YAML

openapi: 3.0.3
info:
title: Oikos API
version: 1.0.0
contact:
name: dtoro
license:
name: Private
url: https://example.invalid/private
description: 'Control-plane API for the Oikos homelab OS. This file is the **source of
truth** (contract-first): Go server stubs are generated with oapi-codegen,
clients (homelab CLI, future UIs) from the same spec.
Conventions (plan R3-3):
- Errors are RFC 9457 `application/problem+json`.
- Lists use `{items, next_cursor}` with cursor pagination (default limit 50, max 200).
- Unsafe POSTs accept `Idempotency-Key` (24h replay window).
- Mutable resources carry `version`; GET returns `ETag`, PATCH requires `If-Match` (412 on mismatch).
- Timestamps are RFC 3339 UTC.
- Entities are addressable by UUID or slug (`host:hubris`).
The MCP interface (streamable HTTP, official Go SDK) is mounted at `/mcp`
on the same binary and is out of scope for this document; its tools wrap
the same service layer as these endpoints.
'
servers:
- url: /api/v1
tags:
- name: entities
description: Inventory graph — entities and relationships
- name: clients
description: Client enrollment, context distribution, secrets
- name: ontology
description: Entity types, relationship types, lifecycles
- name: signals
description: Signals and checks (observe)
- name: executions
description: Executions, classifications, approvals (decide/act)
- name: learning
description: Patterns and skills (learn)
- name: policy
description: Risk classes, approval rules, autonomy
- name: knowledge
description: Knowledge graph search
- name: observability
description: Metrics, trends, audit, events, health
- name: system
description: Export, health
security:
- bearerAuth: []
paths:
/entities:
get:
tags:
- entities
operationId: listEntities
summary: List entities
x-required-scope: viewer
parameters:
- name: type
in: query
schema:
type: string
description: Filter by entity type (includes descendants)
- name: state
in: query
schema:
type: string
- name: domain
in: query
schema:
type: string
- name: layer
in: query
schema:
type: string
- name: q
in: query
schema:
type: string
description: Substring match on slug/name
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Entity list
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Entity'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
post:
tags:
- entities
operationId: createEntity
summary: Create an entity
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EntityCreate'
responses:
'201':
description: Created
headers:
ETag:
$ref: '#/components/headers/ETag'
content:
application/json:
schema:
$ref: '#/components/schemas/Entity'
default:
$ref: '#/components/responses/Problem'
/entities/{id}:
parameters:
- $ref: '#/components/parameters/EntityId'
get:
tags:
- entities
operationId: getEntity
summary: Get entity by UUID or slug
x-required-scope: viewer
responses:
'200':
description: Entity detail
headers:
ETag:
$ref: '#/components/headers/ETag'
content:
application/json:
schema:
$ref: '#/components/schemas/Entity'
default:
$ref: '#/components/responses/Problem'
patch:
tags:
- entities
operationId: patchEntity
summary: Update attributes or transition lifecycle state
description: 'Lifecycle transitions are validated against the type''s lifecycle_def;
illegal transitions return 409 (invalid-transition). Policy-gated
actions may return 403 (approval-required).
'
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IfMatch'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EntityPatch'
responses:
'200':
description: Updated entity
headers:
ETag:
$ref: '#/components/headers/ETag'
content:
application/json:
schema:
$ref: '#/components/schemas/Entity'
default:
$ref: '#/components/responses/Problem'
/entities/{id}/relations:
parameters:
- $ref: '#/components/parameters/EntityId'
get:
tags:
- entities
operationId: getEntityRelations
summary: Direct relationships of an entity (both directions)
x-required-scope: viewer
parameters:
- name: rel_type
in: query
schema:
type: string
- name: direction
in: query
schema:
type: string
enum:
- out
- in
- both
default: both
responses:
'200':
description: Relationships
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Relationship'
default:
$ref: '#/components/responses/Problem'
/relationships:
post:
tags:
- entities
operationId: createRelationship
summary: Create a relationship edge
description: Endpoint types validated against relationship_types (hierarchy-aware); cardinality
enforced.
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RelationshipCreate'
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/Relationship'
default:
$ref: '#/components/responses/Problem'
delete:
tags:
- entities
operationId: endRelationship
summary: End a relationship (sets valid_to; the edge is kept for history)
x-required-scope: operator
parameters:
- name: source
in: query
required: true
schema:
type: string
- name: target
in: query
required: true
schema:
type: string
- name: rel_type
in: query
required: true
schema:
type: string
responses:
'204':
description: Relationship ended
default:
$ref: '#/components/responses/Problem'
/graph:
get:
tags:
- entities
operationId: getGraph
summary: Subgraph for visualization (nodes + edges)
x-required-scope: viewer
parameters:
- name: root
in: query
schema:
type: string
description: Start entity (UUID or slug); omit for whole graph (capped)
- name: depth
in: query
schema:
type: integer
default: 2
maximum: 5
- name: rel_type
in: query
schema:
type: array
items:
type: string
style: form
explode: true
- name: include
in: query
schema:
type: array
items:
type: string
enum:
- status
style: form
explode: true
description: include=status joins entity_status and populates GraphView.health
responses:
'200':
description: Graph view
content:
application/json:
schema:
$ref: '#/components/schemas/GraphView'
default:
$ref: '#/components/responses/Problem'
/entities/{id}/blast-radius:
parameters:
- $ref: '#/components/parameters/EntityId'
get:
tags:
- entities
operationId: getBlastRadius
summary: Entities affected if this entity fails
x-required-scope: viewer
parameters:
- name: depth
in: query
schema:
type: integer
default: 3
maximum: 5
responses:
'200':
description: Affected entities with graph distance
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
type: object
required:
- entity
- depth
properties:
entity:
$ref: '#/components/schemas/Entity'
depth:
type: integer
default:
$ref: '#/components/responses/Problem'
/clients/enroll:
post:
tags:
- clients
operationId: enrollClient
summary: Enroll a new client — issue age key, create Infisical identity
description: >
Validates mesh IP, generates an age keypair, creates an Infisical
machine identity, and transitions the entity to provisioning.
Caller must already have an entity in planned or provisioning state.
x-required-scope: agent
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EnrollRequest'
responses:
'200':
description: Enrollment response with keys and identity
content:
application/json:
schema:
$ref: '#/components/schemas/EnrollResponse'
default:
$ref: '#/components/responses/Problem'
/clients/{slug}/context:
parameters:
- $ref: '#/components/parameters/EntitySlug'
get:
tags:
- clients
operationId: getClientContext
summary: Get agent context delta since a timestamp
description: >
Returns which agent files, tools, and SOPS config changed since the
given timestamp. Thin clients poll this instead of git pull.
x-required-scope: agent
parameters:
- name: since
in: query
schema:
type: string
format: date-time
description: Return only changes since this timestamp (RFC 3339)
responses:
'200':
description: Context delta
content:
application/json:
schema:
$ref: '#/components/schemas/ClientContext'
default:
$ref: '#/components/responses/Problem'
/clients/{slug}/secrets:
parameters:
- $ref: '#/components/parameters/EntitySlug'
get:
tags:
- clients
operationId: getClientSecrets
summary: List secrets accessible to this client
description: Infisical-secured secrets scoped to the client's machine identity
x-required-scope: agent
responses:
'200':
description: Secret keys accessible to this client
content:
application/json:
schema:
$ref: '#/components/schemas/ClientSecrets'
default:
$ref: '#/components/responses/Problem'
/entities/provision:
post:
tags:
- entities
operationId: provisionEntity
summary: Provision a compute entity (LXC, VM, container) on a host
description: >
Creates the entity in planned state, validates constraints (VMID, IP,
capacity, template), classifies the action against policy, and
transitions to provisioning on operator approval.
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProvisionRequest'
responses:
'201':
description: Entity created, provisioning queued
headers:
ETag:
$ref: '#/components/headers/ETag'
content:
application/json:
schema:
$ref: '#/components/schemas/ProvisionResponse'
default:
$ref: '#/components/responses/Problem'
/entities/{slug}/provision/status:
parameters:
- $ref: '#/components/parameters/EntitySlug'
get:
tags:
- entities
operationId: getProvisionStatus
summary: Poll provisioning progress for a compute entity
x-required-scope: viewer
responses:
'200':
description: Provisioning steps with status
content:
application/json:
schema:
$ref: '#/components/schemas/ProvisionStatus'
default:
$ref: '#/components/responses/Problem'
/ontology:
get:
tags:
- ontology
operationId: getOntology
summary: Full ontology — entity types, relationship types, lifecycles
x-required-scope: viewer
responses:
'200':
description: Ontology
content:
application/json:
schema:
type: object
required:
- entity_types
- relationship_types
- lifecycles
properties:
entity_types:
type: array
items:
$ref: '#/components/schemas/EntityType'
relationship_types:
type: array
items:
$ref: '#/components/schemas/RelationshipType'
lifecycles:
type: array
items:
$ref: '#/components/schemas/LifecycleDef'
default:
$ref: '#/components/responses/Problem'
/ontology/entity-types:
post:
tags:
- ontology
operationId: createEntityType
summary: Extend the ontology with a new entity type
description: Policy-gated as config_mutation (creates a meta-approval when required).
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EntityTypeCreate'
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/EntityType'
'202':
$ref: '#/components/responses/PendingApproval'
default:
$ref: '#/components/responses/Problem'
/ontology/entity-types/{name}:
parameters:
- name: name
in: path
required: true
schema:
type: string
patch:
tags:
- ontology
operationId: patchEntityType
summary: Update or deprecate an entity type
description: Hard delete is not supported while instances exist — deprecate instead (plan D3).
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IfMatch'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EntityTypePatch'
responses:
'200':
description: Updated
content:
application/json:
schema:
$ref: '#/components/schemas/EntityType'
'202':
$ref: '#/components/responses/PendingApproval'
default:
$ref: '#/components/responses/Problem'
/signals:
get:
tags:
- signals
operationId: listSignals
summary: List signals
x-required-scope: viewer
parameters:
- name: state
in: query
schema:
type: string
- name: severity
in: query
schema:
type: string
enum:
- info
- warning
- critical
- name: entity_id
in: query
schema:
type: string
- name: kind
in: query
schema:
type: string
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Signals
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Signal'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
/signals/{id}/ack:
parameters:
- $ref: '#/components/parameters/EntityId'
post:
tags:
- signals
operationId: ackSignal
summary: Acknowledge a signal
x-required-scope: operator
responses:
'200':
$ref: '#/components/responses/SignalUpdated'
default:
$ref: '#/components/responses/Problem'
/signals/{id}/resolve:
parameters:
- $ref: '#/components/parameters/EntityId'
post:
tags:
- signals
operationId: resolveSignal
summary: Resolve a signal manually
x-required-scope: operator
requestBody:
content:
application/json:
schema:
type: object
properties:
note:
type: string
responses:
'200':
$ref: '#/components/responses/SignalUpdated'
default:
$ref: '#/components/responses/Problem'
/signals/{id}/mute:
parameters:
- $ref: '#/components/parameters/EntityId'
post:
tags:
- signals
operationId: muteSignal
summary: Mute a signal for a TTL
x-required-scope: operator
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- mute_until
properties:
mute_until:
type: string
format: date-time
note:
type: string
responses:
'200':
$ref: '#/components/responses/SignalUpdated'
default:
$ref: '#/components/responses/Problem'
/checks:
get:
tags:
- signals
operationId: listChecks
summary: List check definitions
x-required-scope: viewer
parameters:
- name: kind
in: query
schema:
type: string
- name: target
in: query
schema:
type: string
- name: enabled
in: query
schema:
type: boolean
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Checks
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Check'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
post:
tags:
- signals
operationId: createCheck
summary: Create a check (checks-as-data, plan R3-7)
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CheckCreate'
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/Check'
default:
$ref: '#/components/responses/Problem'
/checks/{id}:
parameters:
- $ref: '#/components/parameters/EntityId'
patch:
tags:
- signals
operationId: patchCheck
summary: Update or disable a check
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IfMatch'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CheckPatch'
responses:
'200':
description: Updated
content:
application/json:
schema:
$ref: '#/components/schemas/Check'
default:
$ref: '#/components/responses/Problem'
/executions:
get:
tags:
- executions
operationId: listExecutions
summary: List executions
x-required-scope: viewer
parameters:
- name: status
in: query
schema:
type: string
- name: target
in: query
schema:
type: string
- name: action
in: query
schema:
type: string
- name: correlation_id
in: query
schema:
type: string
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Executions
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Execution'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
post:
tags:
- executions
operationId: requestExecution
summary: Request an execution (classify → approval check → enqueue)
description: 'The handler classifies the (entity, action), checks policy/autonomy,
and either enqueues the execution (auto-approved) or creates an
approval request and returns the execution in `proposed` state.
Also exposed to the agent role — this is the ONLY way agents act.
'
x-required-scope: agent
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ExecutionRequest'
responses:
'201':
description: Execution created (may be pending approval)
content:
application/json:
schema:
$ref: '#/components/schemas/Execution'
default:
$ref: '#/components/responses/Problem'
/executions/{id}:
parameters:
- $ref: '#/components/parameters/EntityId'
get:
tags:
- executions
operationId: getExecution
summary: Execution status + result
x-required-scope: viewer
responses:
'200':
description: Execution
content:
application/json:
schema:
$ref: '#/components/schemas/Execution'
default:
$ref: '#/components/responses/Problem'
/executions/{id}/cancel:
parameters:
- $ref: '#/components/parameters/EntityId'
post:
tags:
- executions
operationId: cancelExecution
summary: Cancel a proposed/executing execution
x-required-scope: operator
responses:
'200':
description: Cancelled
content:
application/json:
schema:
$ref: '#/components/schemas/Execution'
default:
$ref: '#/components/responses/Problem'
/classifications:
get:
tags:
- executions
operationId: listClassifications
summary: Classifier decisions (the autonomous-decision audit trail)
x-required-scope: viewer
parameters:
- name: signal_id
in: query
schema:
type: string
- name: entity_id
in: query
schema:
type: string
- name: route
in: query
schema:
type: string
enum:
- auto-act
- escalate
- hold
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Classifications
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Classification'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
/approvals:
get:
tags:
- executions
operationId: listApprovals
summary: List approvals
x-required-scope: viewer
parameters:
- name: status
in: query
schema:
type: string
enum:
- pending
- approved
- denied
- expired
- revoked
- name: kind
in: query
schema:
type: string
enum:
- execution
- policy-change
- pattern-activation
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Approvals
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Approval'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
/approvals/{id}/decision:
parameters:
- $ref: '#/components/parameters/EntityId'
post:
tags:
- executions
operationId: decideApproval
summary: Approve or deny (single-use token verified server-side)
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- decision
properties:
decision:
type: string
enum:
- approve
- deny
- revoke
note:
type: string
token:
type: string
description: HMAC approval token (single-use, verified server-side)
responses:
'200':
description: Decision recorded
content:
application/json:
schema:
$ref: '#/components/schemas/Approval'
default:
$ref: '#/components/responses/Problem'
/patterns:
get:
tags:
- learning
operationId: listPatterns
summary: List patterns
x-required-scope: viewer
parameters:
- name: entity_type
in: query
schema:
type: string
- name: action
in: query
schema:
type: string
- name: status
in: query
schema:
type: string
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Patterns
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Pattern'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
/patterns/{id}:
parameters:
- $ref: '#/components/parameters/EntityId'
patch:
tags:
- learning
operationId: patchPattern
summary: Transition a pattern (activate / invalidate / deprecate)
description: Operator safety valve (plan SG7). Activation is policy-gated config_mutation (S4).
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IfMatch'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum:
- validated
- active
- deprecated
- invalidated
quarantined:
type: boolean
note:
type: string
responses:
'200':
description: Updated
content:
application/json:
schema:
$ref: '#/components/schemas/Pattern'
'202':
$ref: '#/components/responses/PendingApproval'
default:
$ref: '#/components/responses/Problem'
/skills:
get:
tags:
- learning
operationId: listSkills
summary: List skills (latest version per skill)
x-required-scope: viewer
parameters:
- name: applies_to
in: query
schema:
type: string
- name: action
in: query
schema:
type: string
- name: status
in: query
schema:
type: string
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Skills
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Skill'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
/skills/{id}:
parameters:
- $ref: '#/components/parameters/EntityId'
patch:
tags:
- learning
operationId: patchSkill
summary: Transition a skill or pin a version
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IfMatch'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum:
- tested
- active
- deprecated
pinned_version:
type: integer
note:
type: string
responses:
'200':
description: Updated
content:
application/json:
schema:
$ref: '#/components/schemas/Skill'
'202':
$ref: '#/components/responses/PendingApproval'
default:
$ref: '#/components/responses/Problem'
/skills/{id}/versions:
parameters:
- $ref: '#/components/parameters/EntityId'
get:
tags:
- learning
operationId: listSkillVersions
summary: Version history of a skill
x-required-scope: viewer
responses:
'200':
description: Versions
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Skill'
default:
$ref: '#/components/responses/Problem'
/policy/risk-classes:
get:
tags:
- policy
operationId: listRiskClasses
summary: List risk classes
x-required-scope: viewer
responses:
'200':
description: Risk classes
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/RiskClass'
default:
$ref: '#/components/responses/Problem'
/policy/approval-rules:
get:
tags:
- policy
operationId: listApprovalRules
summary: List approval rules
x-required-scope: viewer
responses:
'200':
description: Rules
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/ApprovalRule'
default:
$ref: '#/components/responses/Problem'
post:
tags:
- policy
operationId: createApprovalRule
summary: Propose a new approval rule (dual-control)
description: Creates a policy-change approval; the rule applies only after operator approval (plan
S3).
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ApprovalRuleCreate'
responses:
'202':
$ref: '#/components/responses/PendingApproval'
default:
$ref: '#/components/responses/Problem'
/policy/approval-rules/{id}:
parameters:
- $ref: '#/components/parameters/EntityId'
patch:
tags:
- policy
operationId: patchApprovalRule
summary: Propose a rule change (dual-control)
x-required-scope: operator
parameters:
- $ref: '#/components/parameters/IfMatch'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ApprovalRuleCreate'
responses:
'202':
$ref: '#/components/responses/PendingApproval'
default:
$ref: '#/components/responses/Problem'
/policy/autonomy:
get:
tags:
- policy
operationId: getAutonomySettings
summary: Autonomy settings (kill-switch, never-auto-act list)
x-required-scope: viewer
responses:
'200':
description: Settings
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/AutonomySetting'
default:
$ref: '#/components/responses/Problem'
patch:
tags:
- policy
operationId: patchAutonomySettings
summary: Propose autonomy changes (dual-control; kill-switch OFF is immediate)
description: 'Raising autonomy is dual-controlled (202 + approval). Lowering it —
setting `global.auto_act: "off"` or adding a never_auto_act key —
applies immediately (200): the kill-switch must never wait for an approval.
'
x-required-scope: operator
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties:
type: string
responses:
'200':
description: Applied (restriction)
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/AutonomySetting'
'202':
$ref: '#/components/responses/PendingApproval'
default:
$ref: '#/components/responses/Problem'
/knowledge/search:
get:
tags:
- knowledge
operationId: searchKnowledge
summary: Full-text search over knowledge entities (documents, runbooks)
x-required-scope: viewer
parameters:
- name: q
in: query
required: true
schema:
type: string
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Hits
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/KnowledgeHit'
default:
$ref: '#/components/responses/Problem'
/knowledge/{entity_id}:
parameters:
- name: entity_id
in: path
required: true
schema:
type: string
get:
tags:
- knowledge
operationId: getEntityKnowledge
summary: All documents/runbooks linked to an entity
x-required-scope: viewer
responses:
'200':
description: Linked knowledge
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/KnowledgeHit'
default:
$ref: '#/components/responses/Problem'
/metrics:
get:
tags:
- observability
operationId: queryMetrics
summary: Query time-series metrics
x-required-scope: viewer
parameters:
- name: entity_id
in: query
schema:
type: string
- name: metric
in: query
schema:
type: array
items:
type: string
style: form
explode: true
- name: rollup
in: query
schema:
type: string
enum:
- raw
- 1h
- 1d
- auto
default: auto
- $ref: '#/components/parameters/FromTime'
- $ref: '#/components/parameters/ToTime'
responses:
'200':
description: Metric series
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/MetricSeries'
default:
$ref: '#/components/responses/Problem'
/trends/{entity_id}:
parameters:
- name: entity_id
in: path
required: true
schema:
type: string
get:
tags:
- observability
operationId: getTrends
summary: Trend analysis for all metrics on an entity
x-required-scope: viewer
parameters:
- $ref: '#/components/parameters/FromTime'
- $ref: '#/components/parameters/ToTime'
responses:
'200':
description: Trends
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Trend'
default:
$ref: '#/components/responses/Problem'
/audit:
get:
tags:
- observability
operationId: queryAudit
summary: Audit log
x-required-scope: operator
parameters:
- name: actor_type
in: query
schema:
type: string
- name: actor_id
in: query
schema:
type: string
- name: entity_id
in: query
schema:
type: string
- name: action
in: query
schema:
type: string
- name: correlation_id
in: query
schema:
type: string
- $ref: '#/components/parameters/FromTime'
- $ref: '#/components/parameters/ToTime'
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Audit entries (ts DESC)
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/AuditEntry'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
/events:
get:
tags:
- observability
operationId: queryEvents
summary: Historical events
x-required-scope: viewer
parameters:
- name: type
in: query
schema:
type: string
- name: entity_id
in: query
schema:
type: string
- name: severity
in: query
schema:
type: string
- name: correlation_id
in: query
schema:
type: string
- $ref: '#/components/parameters/FromTime'
- $ref: '#/components/parameters/ToTime'
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Events (ts DESC)
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/Event'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
/events/stream:
get:
tags:
- observability
operationId: streamEvents
summary: Live event stream (SSE)
description: 'Server-Sent Events. Each event''s `id` is the event row id (resume
with `Last-Event-ID`), `event` is the event type, `data` is the JSON
Event object. Heartbeat comments every 15s. Best-effort delivery —
bounded per-subscriber buffer, drop-oldest (plan P6); use GET /events
to backfill.
'
x-required-scope: viewer
parameters:
- name: type
in: query
schema:
type: string
description: Filter by event type prefix
- name: Last-Event-ID
in: header
schema:
type: string
responses:
'200':
description: SSE stream
content:
text/event-stream:
schema:
type: string
default:
$ref: '#/components/responses/Problem'
/agent-activity:
get:
tags:
- observability
operationId: queryAgentActivity
summary: Agent behavior log
x-required-scope: viewer
parameters:
- name: agent_id
in: query
schema:
type: string
- name: activity_type
in: query
schema:
type: string
- name: entity_id
in: query
schema:
type: string
- $ref: '#/components/parameters/FromTime'
- $ref: '#/components/parameters/ToTime'
- $ref: '#/components/parameters/Cursor'
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Activity entries
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
items:
$ref: '#/components/schemas/AgentActivity'
next_cursor:
type: string
nullable: true
default:
$ref: '#/components/responses/Problem'
/health:
get:
tags:
- observability
operationId: getFleetHealth
summary: Fleet health summary with trend indicators
x-required-scope: viewer
responses:
'200':
description: Health summary
content:
application/json:
schema:
$ref: '#/components/schemas/HealthSummary'
default:
$ref: '#/components/responses/Problem'
/dashboard/summary:
get:
tags:
- observability
operationId: getDashboardSummary
summary: One-round-trip overview for the control room home page
x-required-scope: viewer
responses:
'200':
description: Dashboard summary
content:
application/json:
schema:
$ref: '#/components/schemas/DashboardSummary'
default:
$ref: '#/components/responses/Problem'
/export:
get:
tags:
- system
operationId: exportSeeds
summary: Regenerate seed YAMLs from current DB state (DR / version control)
x-required-scope: operator
responses:
'200':
description: Seed bundle
content:
application/json:
schema:
type: object
required:
- ontology
- inventory
- policy
properties:
ontology:
type: string
description: YAML document
inventory:
type: string
description: YAML document
policy:
type: string
description: YAML document
default:
$ref: '#/components/responses/Problem'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: 'Operator/viewer: Authentik OIDC JWT (validated in-API — Caddy
forward-auth is defense-in-depth, not the source of truth).
Agent: static bearer token from Infisical (scope `agent`).
'
parameters:
EntityId:
name: id
in: path
required: true
schema:
type: string
description: UUID or slug (e.g. `host:hubris`)
Cursor:
name: cursor
in: query
schema:
type: string
description: Opaque cursor from a previous response's next_cursor
Limit:
name: limit
in: query
schema:
type: integer
default: 50
maximum: 200
minimum: 1
FromTime:
name: from
in: query
schema:
type: string
format: date-time
ToTime:
name: to
in: query
schema:
type: string
format: date-time
IfMatch:
name: If-Match
in: header
required: true
schema:
type: string
description: ETag from a prior GET; 412 on version mismatch
IdempotencyKey:
name: Idempotency-Key
in: header
schema:
type: string
maxLength: 128
description: Client-generated key; replays within 24h return the original response
EntitySlug:
name: slug
in: path
required: true
schema:
type: string
description: Entity slug (e.g. `ws:mac-mini`, `lxc:caddy`)
headers:
ETag:
schema:
type: string
description: Resource version for If-Match
responses:
Problem:
description: Error (RFC 9457)
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
PendingApproval:
description: Change staged; a meta-approval was created (dual-control)
content:
application/json:
schema:
$ref: '#/components/schemas/Approval'
SignalUpdated:
description: Updated signal
content:
application/json:
schema:
$ref: '#/components/schemas/Signal'
schemas:
Problem:
type: object
required:
- title
- status
properties:
type:
type: string
format: uri
default: about:blank
title:
type: string
status:
type: integer
detail:
type: string
instance:
type: string
errors:
type: array
description: Field-level validation errors (422)
items:
type: object
required:
- field
- reason
properties:
field:
type: string
reason:
type: string
Entity:
type: object
required:
- id
- slug
- type
- name
- version
- created_at
- updated_at
properties:
id:
type: string
format: uuid
slug:
type: string
example: host:hubris
type:
type: string
name:
type: string
state:
type: string
nullable: true
attributes:
type: object
maintenance_until:
type: string
format: date-time
nullable: true
version:
type: integer
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
health:
type: string
description: last observed health, when the entity is monitored
nullable: true
enum:
- healthy
- degraded
- down
- unknown
- stale
last_check_at:
type: string
format: date-time
nullable: true
description: when health was last observed
EntityCreate:
type: object
required:
- slug
- type
- name
properties:
slug:
type: string
type:
type: string
description: Must be a non-abstract entity type
name:
type: string
state:
type: string
description: Defaults to the lifecycle's default_state
attributes:
type: object
description: Validated against the type's attribute_schema
EntityPatch:
type: object
description: At least one of the fields must be present.
properties:
name:
type: string
state:
type: string
description: Target lifecycle state (transition validated)
attributes:
type: object
description: Merged; validated against attribute_schema
maintenance_until:
type: string
format: date-time
nullable: true
Relationship:
type: object
required:
- source
- target
- type
- valid_from
properties:
source:
type: string
description: Slug of source entity
target:
type: string
description: Slug of target entity
type:
type: string
attributes:
type: object
nullable: true
valid_from:
type: string
format: date-time
valid_to:
type: string
format: date-time
nullable: true
RelationshipCreate:
type: object
required:
- source
- target
- type
properties:
source:
type: string
description: UUID or slug
target:
type: string
description: UUID or slug
type:
type: string
attributes:
type: object
GraphView:
type: object
required:
- nodes
- edges
properties:
nodes:
type: array
items:
$ref: '#/components/schemas/Entity'
edges:
type: array
items:
$ref: '#/components/schemas/Relationship'
truncated:
type: boolean
description: True if node cap was hit
health:
type: object
description: entity id -> health, present when include=status was requested
additionalProperties:
type: string
enum:
- healthy
- degraded
- down
- unknown
- stale
EntityType:
type: object
required:
- name
- domain
- layer
- is_abstract
- status
properties:
name:
type: string
parent_type:
type: string
nullable: true
is_abstract:
type: boolean
domain:
type: string
layer:
type: string
enum:
- meta
- infrastructure
- governance
- cognition
description:
type: string
lifecycle_id:
type: string
nullable: true
attribute_schema:
type: object
description: JSON Schema
nullable: true
schema_version:
type: integer
status:
type: string
enum:
- active
- deprecated
version:
type: integer
EntityTypeCreate:
type: object
required:
- name
- domain
- layer
properties:
name:
type: string
parent_type:
type: string
is_abstract:
type: boolean
default: false
domain:
type: string
layer:
type: string
enum:
- infrastructure
- governance
- cognition
description:
type: string
lifecycle_id:
type: string
attribute_schema:
type: object
EntityTypePatch:
type: object
properties:
description:
type: string
attribute_schema:
type: object
status:
type: string
enum:
- active
- deprecated
RelationshipType:
type: object
required:
- name
- source_type
- target_type
- cardinality
properties:
name:
type: string
inverse:
type: string
nullable: true
source_type:
type: string
description: May be abstract
target_type:
type: string
description: May be abstract
cardinality:
type: string
enum:
- one-to-one
- one-to-many
- many-to-one
- many-to-many
description:
type: string
LifecycleDef:
type: object
required:
- id
- states
- default_state
- transitions
properties:
id:
type: string
states:
type: array
items:
type: string
default_state:
type: string
terminal_states:
type: array
items:
type: string
transitions:
type: object
description: '{from: {to: {requires: [named-check, ...]}}}'
Signal:
type: object
required:
- id
- slug
- kind
- severity
- state
- occurrence_count
- first_seen_at
- last_seen_at
properties:
id:
type: string
format: uuid
slug:
type: string
kind:
type: string
example: service-down
severity:
type: string
enum:
- info
- warning
- critical
state:
type: string
enum:
- raised
- acknowledged
- acting
- muted
- resolved
- failed
target:
type: string
description: Slug of the entity this concerns
nullable: true
check_id:
type: string
nullable: true
evidence:
type: string
nullable: true
likely_cause:
type: string
nullable: true
occurrence_count:
type: integer
flap_count:
type: integer
hold_down_until:
type: string
format: date-time
nullable: true
mute_until:
type: string
format: date-time
nullable: true
first_seen_at:
type: string
format: date-time
last_seen_at:
type: string
format: date-time
Check:
type: object
required:
- id
- slug
- kind
- interval_s
- timeout_s
- enabled
- version
properties:
id:
type: string
format: uuid
slug:
type: string
kind:
type: string
enum:
- http
- tcp
- disk
- cert-expiry
- drift
- ping
- ssh-script
target:
type: string
description: Entity slug (instance-scoped)
nullable: true
target_type:
type: string
description: Entity type (type-scoped)
nullable: true
config:
type: object
description: Validated per-kind
interval_s:
type: integer
timeout_s:
type: integer
zone:
type: string
nullable: true
enabled:
type: boolean
version:
type: integer
last_health:
type: string
description: >-
This check's own most recent verdict. An entity's health is the
worst of these across its enabled checks, so this is what explains
*why* an entity is degraded. Null until the check first runs.
nullable: true
enum:
- healthy
- degraded
- down
- unknown
last_run_at:
type: string
format: date-time
description: When this check last executed. Null = never run.
nullable: true
CheckCreate:
type: object
required:
- slug
- kind
properties:
slug:
type: string
kind:
type: string
enum:
- http
- tcp
- disk
- cert-expiry
- drift
- ping
- ssh-script
target:
type: string
target_type:
type: string
config:
type: object
interval_s:
type: integer
default: 600
timeout_s:
type: integer
default: 10
zone:
type: string
enabled:
type: boolean
default: true
CheckPatch:
type: object
properties:
config:
type: object
interval_s:
type: integer
timeout_s:
type: integer
enabled:
type: boolean
Execution:
type: object
required:
- id
- slug
- action
- risk_class
- status
- correlation_id
- created_at
properties:
id:
type: string
format: uuid
slug:
type: string
target:
type: string
nullable: true
action:
type: string
risk_class:
type: string
status:
type: string
enum:
- proposed
- approved
- auto_approved
- denied
- expired
- executing
- verifying
- verified
- failed
- timed_out
- cancelled
- rolled_back
- rollback_failed
classification_id:
type: string
nullable: true
signal_id:
type: string
nullable: true
approval_id:
type: string
nullable: true
agent_id:
type: string
nullable: true
skill_id:
type: string
nullable: true
skill_version:
type: integer
nullable: true
params:
type: object
description: Skill params (validated against params_schema)
result:
type: object
nullable: true
duration_ms:
type: integer
nullable: true
verified:
type: boolean
correlation_id:
type: string
started_at:
type: string
format: date-time
nullable: true
completed_at:
type: string
format: date-time
nullable: true
created_at:
type: string
format: date-time
ExecutionRequest:
type: object
required:
- target
- action
properties:
target:
type: string
description: Entity UUID or slug
action:
type: string
example: restart
params:
type: object
signal_id:
type: string
description: Signal that motivated this (optional)
reason:
type: string
Classification:
type: object
required:
- id
- action
- risk_class
- route
- reasoning
- correlation_id
- created_at
properties:
id:
type: string
format: uuid
signal_id:
type: string
nullable: true
target:
type: string
nullable: true
action:
type: string
recommended_action:
type: object
nullable: true
risk_class:
type: string
route:
type: string
enum:
- auto-act
- escalate
- hold
blast_radius:
type: array
items:
type: string
pattern_confidence:
type: number
nullable: true
skill_id:
type: string
nullable: true
autonomy_check:
type: string
reasoning:
type: object
correlation_id:
type: string
created_at:
type: string
format: date-time
Approval:
type: object
required:
- id
- slug
- action
- risk_class
- kind
- status
- expires_at
- created_at
properties:
id:
type: string
format: uuid
slug:
type: string
subject:
type: string
description: Entity slug the approval concerns
nullable: true
action:
type: string
risk_class:
type: string
kind:
type: string
enum:
- execution
- policy-change
- pattern-activation
payload:
type: object
description: e.g. proposed policy diff
nullable: true
status:
type: string
enum:
- pending
- approved
- denied
- expired
- revoked
expires_at:
type: string
format: date-time
decided_at:
type: string
format: date-time
nullable: true
decided_by:
type: string
nullable: true
created_at:
type: string
format: date-time
Pattern:
type: object
required:
- id
- slug
- applies_type
- action
- pattern
- confidence
- evidence_count
- status
- version
properties:
id:
type: string
format: uuid
slug:
type: string
applies_type:
type: string
action:
type: string
pattern:
type: string
confidence:
type: number
description: Wilson lower bound, capped by evidence_count/5
evidence_count:
type: integer
success_count:
type: integer
failure_count:
type: integer
status:
type: string
enum:
- hypothesized
- validated
- active
- deprecated
- invalidated
quarantined:
type: boolean
version:
type: integer
last_validated_at:
type: string
format: date-time
nullable: true
Skill:
type: object
required:
- id
- slug
- name
- version
- action
- status
- procedure
properties:
id:
type: string
format: uuid
slug:
type: string
name:
type: string
version:
type: integer
action:
type: string
applies_type:
type: string
nullable: true
procedure:
type: object
description: Structured steps/verify/rollback/params (plan R3-9)
required:
- steps
- verify
properties:
params_schema:
type: object
steps:
type: array
items:
$ref: '#/components/schemas/SkillStep'
verify:
type: array
items:
$ref: '#/components/schemas/SkillStep'
rollback:
type: array
items:
$ref: '#/components/schemas/SkillStep'
expected_duration_s:
type: integer
known_failure_modes:
type: array
items:
type: string
pattern_ids:
type: array
items:
type: string
status:
type: string
enum:
- drafted
- tested
- active
- refined
- failed
- deprecated
success_rate:
type: number
nullable: true
changed_by:
type: string
nullable: true
change_reason:
type: string
nullable: true
last_used_at:
type: string
format: date-time
nullable: true
SkillStep:
type: object
required:
- runner
- command
properties:
name:
type: string
runner:
type: string
enum:
- ssh
- http
- internal
target:
type: string
description: Go template over params
command:
type: string
description: Go template over params
timeout_s:
type: integer
default: 60
expect:
type: object
properties:
exit_code:
type: integer
stdout_contains:
type: string
retry:
type: object
properties:
attempts:
type: integer
delay_s:
type: integer
RiskClass:
type: object
required:
- name
- approval_required
- autonomy_allowed
properties:
name:
type: string
description:
type: string
approval_required:
type: string
enum:
- none
- operator
- operator_confirmed
autonomy_allowed:
type: boolean
ApprovalRule:
type: object
required:
- id
- action
- risk_class
- autonomy_level
- version
properties:
id:
type: string
format: uuid
entity_type:
type: string
description: May be abstract (inherits down)
nullable: true
action:
type: string
risk_class:
type: string
autonomy_level:
type: string
enum:
- auto
- escalate
- never
scope_entity:
type: string
description: Entity slug for per-entity overrides
nullable: true
version:
type: integer
ApprovalRuleCreate:
type: object
required:
- action
- risk_class
- autonomy_level
properties:
entity_type:
type: string
action:
type: string
risk_class:
type: string
autonomy_level:
type: string
enum:
- auto
- escalate
- never
scope_entity:
type: string
AutonomySetting:
type: object
required:
- key
- value
- version
properties:
key:
type: string
example: global.auto_act
value:
type: string
version:
type: integer
updated_at:
type: string
format: date-time
KnowledgeHit:
type: object
required:
- id
- slug
- type
- title
properties:
id:
type: string
format: uuid
slug:
type: string
type:
type: string
enum:
- document
- runbook
- investigation
title:
type: string
source_path:
type: string
nullable: true
snippet:
type: string
description: Highlighted match context
nullable: true
linked_entities:
type: array
items:
type: string
rank:
type: number
nullable: true
MetricSeries:
type: object
required:
- entity_id
- metric
- rollup
- samples
properties:
entity_id:
type: string
metric:
type: string
rollup:
type: string
enum:
- raw
- 1h
- 1d
samples:
type: array
items:
type: object
required:
- ts
properties:
ts:
type: string
format: date-time
value:
type: number
description: Raw sample value
nullable: true
avg:
type: number
nullable: true
min:
type: number
nullable: true
max:
type: number
nullable: true
count:
type: integer
nullable: true
trend:
$ref: '#/components/schemas/Trend'
Trend:
type: object
required:
- metric
- direction
properties:
metric:
type: string
direction:
type: string
enum:
- improving
- degrading
- stable
- unknown
slope:
type: number
description: Linear fit per day
nullable: true
anomaly:
type: boolean
forecast:
type: number
description: Simple linear projection, 7d out
nullable: true
AuditEntry:
type: object
required:
- id
- ts
- actor_type
- action
properties:
id:
type: integer
ts:
type: string
format: date-time
actor_type:
type: string
enum:
- agent
- operator
- system
- scheduler
actor_id:
type: string
nullable: true
action:
type: string
entity_id:
type: string
nullable: true
method:
type: string
nullable: true
path:
type: string
nullable: true
status_code:
type: integer
nullable: true
detail:
type: object
source_ip:
type: string
nullable: true
correlation_id:
type: string
nullable: true
Event:
type: object
required:
- id
- ts
- type
- severity
- source
properties:
id:
type: integer
ts:
type: string
format: date-time
type:
type: string
example: signal.raised
entity_id:
type: string
nullable: true
severity:
type: string
enum:
- info
- warning
- critical
source:
type: string
data:
type: object
correlation_id:
type: string
nullable: true
AgentActivity:
type: object
required:
- id
- ts
- agent_id
- activity_type
properties:
id:
type: integer
ts:
type: string
format: date-time
agent_id:
type: string
session_id:
type: string
nullable: true
activity_type:
type: string
enum:
- tool_call
- reasoning
- decision
- mcp_query
- escalation
tool_name:
type: string
nullable: true
entity_id:
type: string
nullable: true
input_summary:
type: string
nullable: true
output_summary:
type: string
nullable: true
duration_ms:
type: integer
nullable: true
token_count:
type: integer
nullable: true
success:
type: boolean
nullable: true
correlation_id:
type: string
nullable: true
HealthSummary:
type: object
required:
- summary
- entities
properties:
summary:
type: object
required:
- healthy
- degraded
- down
- unknown
properties:
healthy:
type: integer
degraded:
type: integer
down:
type: integer
unknown:
type: integer
stale:
type: integer
description: last observation older than the check's expected cadence
entities:
type: array
items:
type: object
required:
- slug
- type
- health
properties:
slug:
type: string
type:
type: string
health:
type: string
enum:
- healthy
- degraded
- down
- unknown
- stale
trend:
type: string
enum:
- improving
- degrading
- stable
- unknown
nullable: true
last_check_at:
type: string
format: date-time
nullable: true
DashboardSummary:
type: object
required:
- entities_by_type
- entities_by_state
- health
- signals_by_severity
- approvals_pending
- executions_by_state
- event_rate
properties:
entities_by_type:
type: object
description: entity counts keyed by type
additionalProperties:
type: integer
entities_by_state:
type: object
description: entity counts keyed by state
additionalProperties:
type: integer
health:
type: object
required:
- healthy
- degraded
- down
- unknown
properties:
healthy:
type: integer
degraded:
type: integer
down:
type: integer
unknown:
type: integer
stale:
type: integer
description: last observation older than the check's expected cadence
signals_by_severity:
type: object
description: open (non-resolved) signal counts keyed by severity
additionalProperties:
type: integer
approvals_pending:
type: integer
executions_by_state:
type: object
description: execution counts keyed by state, last 24h
additionalProperties:
type: integer
event_rate:
type: array
description: event counts bucketed by 5-minute interval, most recent last
items:
type: object
required:
- bucket
- count
properties:
bucket:
type: string
format: date-time
count:
type: integer
EnrollRequest:
type: object
required:
- slug
properties:
slug:
type: string
description: Entity slug (e.g. ws:new-laptop)
hostname:
type: string
description: Actual hostname of the enrolling machine
mesh_ip:
type: string
description: Source mesh IP for identity validation
EnrollResponse:
type: object
required:
- age_public_key
- age_private_key
- infisical_client_id
- infisical_client_secret
properties:
age_public_key:
type: string
description: age1... public key for SOPS recipients
age_private_key:
type: string
description: AGE-SECRET-KEY-... for local decryption
infisical_client_id:
type: string
description: Infisical UniversalAuth client ID
infisical_client_secret:
type: string
description: Infisical UniversalAuth client secret
machine_identity_token:
type: string
description: Infisical machine identity access token
ClientContext:
type: object
required:
- version
properties:
version:
type: integer
description: Monotonic context version number
agent_files_changed:
type: array
items:
type: string
description: Paths of agent instruction files that changed
sops_config_changed:
type: boolean
description: True if .sops.yaml recipients changed
tools_changed:
type: array
items:
type: string
description: Paths of tools/*.setup.sh that changed
since:
type: string
format: date-time
description: Timestamp for the next poll request
ClientSecrets:
type: object
required:
- keys
properties:
keys:
type: array
items:
type: string
description: Infisical secret keys accessible to this client
ProvisionRequest:
type: object
required:
- slug
- type
- name
- host
properties:
slug:
type: string
description: e.g. lxc:jellyfin
type:
type: string
description: Must be lxc, vm, or docker-container
name:
type: string
description: Human-readable name
host:
type: string
description: Slug of the Proxmox host (e.g. host:hubris)
attributes:
type: object
description: VMID, cores, ram_mb, disk_gb, ip, template, mounts, services
ProvisionResponse:
type: object
required:
- entity
- execution_id
properties:
entity:
$ref: '#/components/schemas/Entity'
execution_id:
type: string
format: uuid
description: Execution ID to track provisioning progress
ProvisionStatus:
type: object
required:
- slug
- state
- steps
properties:
slug:
type: string
state:
type: string
description: Current entity state
steps:
type: array
items:
type: object
required:
- step
- status
properties:
step:
type: string
status:
type: string
enum:
- pending
- running
- ok
- failed
- skipped
error_message:
type: string
nullable: true
started_at:
type: string
format: date-time
nullable: true
finished_at:
type: string
format: date-time
nullable: true
error:
type: string
nullable: true
description: Overall error if provisioning failed