Files
oikos/api/openapi.yaml
dtoro e3449b24c1
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: wire Infisical secret store into API server and MCP tools
- Wire secretsManager in NewHandler() — instantiate InfisicalBackend
  when OIKOS_INFISICAL_SITE_URL is set (previously always nil)
- Add get_secret, list_secrets, set_secret MCP tools with nil-backend
  graceful degradation
- Add oikos secret get|set|list CLI subcommands for Infisical
- Fix Set() bug: create-before-update so new keys are created;
  add Type: "shared" to Update so it finds the right secret;
  disable SDK cache so Get returns fresh data after Set
- Clean enrollment response: remove fake infisical_client_id/
  infisical_client_secret stubs, store age key in Infisical for real
2026-08-05 23:03:27 +02:00

3316 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
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
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