Ops API
The Kaizen application-administrator surface, mounted at /api/ops.
The gate
Every ops route requires the validated platform identity envelope plus either
the trusted Kamiwaza Platform Admin role or owner authority in the current
workroom. Platform administrators retain the complete operator surface.
Workroom owners receive the same Kaizen App Admin controls without gaining
platform-wide inventory authority.
The backend checks this authority on every route. Frontend redirects are only
convenience; removing one does not grant access. Ops actions use the
WEB_ADMIN audit actor so configuration changes remain attributable.
Models
GET /api/ops/models
PUT /api/ops/models/chat
PUT /api/ops/models/embedding
PUT /api/ops/models/reranker
GET /api/ops/setup
Roles, not names. Assigning the embedding role to a deployment that does not serve embeddings is the most common misconfiguration — see Models & embeddings.
GET /api/ops/setup returns one entry per surface it judges, each with a status
and prose an operator can act on. The tasks entry is the one that usually
needs explaining: Tasks can be switched on in this deployment and still be
closed, because the platform has not issued the deployment's workload assertion
or registered its workload roles. That entry says exactly that, and marks itself
attention rather than complete — it is not a launch prerequisite, so a
deployment without Tasks is still ready. Only the diagnostic's own name informs
the copy; no platform URL, claim, or token appears in it.
The sandbox-egress entry is a projection of the effective outbound scope, not
a copy of SANDBOX_EGRESS_MODE: it states the mode in force, the enforced
ports, and the destination classes denied in every mode, and it reports
isolation with the missing prerequisite whenever the configured mode cannot be
enforced. Like the tasks entry it carries classes and switches only — never a
configured host, range, registry, proxy address, or key.
Connectors
Kamiwaza-brokered connectors, discovered at runtime:
GET /api/ops/kamiwaza-connectors
PUT /api/ops/kamiwaza-connectors/{connector_id}
POST /api/ops/kamiwaza-connectors/{connector_id}/rag-actions/{action_id}
Kaizen-managed connector configurations:
GET /api/ops/connectors
POST /api/ops/connectors | /connectors/adopt
GET /api/ops/connectors/{name}
PUT /api/ops/connectors/{name}
DELETE /api/ops/connectors/{name}
POST /api/ops/connectors/{name}/enable | /disable | /resync
Nothing here enumerates connector types. Discovery is dynamic; adding a static catalog would reintroduce release coupling.
Tools
GET /api/ops/kamiwaza-tools
PUT /api/ops/kamiwaza-tools
PUT /api/ops/kamiwaza-tools/{tool_name}
Enabling a tool makes it available to be granted. It does not grant it.
GET /api/ops/kamiwaza-tools returns the current hidden selection-setting
version even though that internal selector is omitted from the general settings
list. Send that value as expected_version on a PUT. A stale value returns
409 version_conflict; a successful write advances the version used by the
next read.
The list combines authenticated Kamiwaza Core OpenAPI operations, MCP Guard
tools, the closed direct-SDK adapters, and—when separately enabled—external
schema sources. The response authors the complete root/source/surface hierarchy;
the frontend does not infer families from display names. A bulk PUT may contain
the returned root selector, source selector, surface selector, or exact tool
name. Root and source selectors are hard ceilings and a true value only permits
narrower selections; it does not grant descendants. A surface true value admits
newly published operations under that same Core tag, SDK surface, MCP server, or
external source automatically, while an exact false entry remains an exception.
The Admin UI implements a parent switch as one CAS-protected bulk PUT with
cascade: true and exactly one returned parent selector. The server resolves the
authenticated subtree. Enabling clears stored endpoint exceptions inside that
subtree and records its surface selectors, while disabling records the parent
ceiling. This makes every effective child checkbox follow the parent without a
request or stored policy proportional to the endpoint count. Calls without
cascade keep the composable selector semantics for other clients.
The SDK source selector is kamiwaza_source:sdk, and its child SDK surface
preserves the closed adapters' prior default until explicitly disabled.
Discovery and writes require the admin role, but the resulting operation still
executes later as the initiating member and is authorized again by Kamiwaza.
The root selector is kamiwaza. Source families use stable returned selectors;
the external source ceiling is external_schema. Each registered external API
is a surface with an external_source:{uuid} selector, management has its own
surface selector, and each endpoint has an exact ext_* name. A false ancestor
is a hard ceiling over exact true entries. This policy controls tool
availability but does not enable network access: the independent
external-capability flag and sandbox-egress policy must also admit the request.
Packages
GET /api/ops/packages
POST /api/ops/packages
GET /api/ops/packages/{id}
POST /api/ops/packages/{id}/upgrade | /disable
DELETE /api/ops/packages/{id}
Agents
GET /api/ops/agents
GET /api/ops/agents/proposals
POST /api/ops/agents/proposals/agent/{id}/approve
POST /api/ops/agents/proposals/package/{id}/approve
POST /api/ops/agents/proposals/{kind}/{id}/reject
POST /api/ops/agents/{id}/enable | /disable | /rollback
GET|PUT /api/ops/agents/{id}/definition
GET /api/ops/agents/{id}/versions
GET /api/ops/agents/{id}/versions/{a}/diff/{b}
Note the asymmetry with the member surface: a member creates a private agent without approval, but publishing to all members is an ops action.
Settings and effective config
GET /api/ops/settings
PUT /api/ops/settings/{key}
DELETE /api/ops/settings/{key}
GET /api/ops/effective-config
POST /api/ops/effective-config/diff
effective-config is the right way to answer "what is this deployment actually
set to?" — reading environment variables off a running container misses
config-store overrides.
Secret values are never disclosed by these endpoints. Configuration carrying a
secret is declared with password metadata in the manifest and is redacted in
responses. A setting response with nullable: true accepts JSON null as an
explicit disabled override; deleting its override instead restores the
environment or packaged default.
Metrics
GET /api/ops/metrics
GET /api/ops/usage?days=7|30|90
GET /api/ops/usage/members?days=7|30|90
The response is a content-free six-hour command-center snapshot. It combines
durable LLM, task, connector, and audit aggregates with process-local request
and sandbox instruments. Every family carries full, partial, or
unavailable coverage, and a missing producer returns value: null rather
than a synthetic zero. The route accepts no member identifier or arbitrary
query and requires Kaizen App Admin authority like every other ops route.
The top-level usage object carries deployment-wide model calls, input,
output, and cache-read tokens plus at most five top_models rows ordered by
call count. Each row includes the bounded model deployment name, call share,
success ratio, and token totals. It never includes a member, agent, task,
conversation, prompt, source, or model output. Model names on this JSON surface
are display dimensions for administrators, not metric labels for Prometheus or
OTLP.
The route is backed by a 30-second process-local single-flight cache. Refreshes use at most two concurrent read-only ledger queries with statement and lock timeouts plus a two-second end-to-end deadline, so multiple polling administrators cannot multiply database work. The task source restricts its scan to the six-hour window and currently live states; concurrent partial indexes support both paths without blocking ledger writes during deployment.
This JSON surface is for the Kaizen admin screen. Monitoring systems should
scrape /metrics or enable the OTLP mirror instead of polling this route.
The separate /usage response is an aggregate-only product-operations view.
Its activity denominator is a message or steering input, not authentication,
presence, or background work. It returns UTC DAU/WAU/MAU, stickiness,
new/returning counts, conversations, completion and first-value measures,
D1/D7/D30 retention, daily activity, per-active-user token distributions,
feature outcomes, and generation/embedding model mix. The only accepted range
is a reviewed 7, 30, or 90 day preset.
The service groups by internal principals to calculate unique counts and token percentiles, but never serializes a principal or per-user row. Prompts, answers, conversations, tool arguments, emails, and model outputs are absent. System/background model calls are excluded from user-attributed consumption. The four source queries are read-only, deadline-bounded, and limited to two concurrent statements; each preset shares a 60-second single-flight cache.
The separate /usage/members response is the content-free per-member view. It
returns at most 100 rows containing a display name, an opaque 12-character
server-derived key, active days, conversations, inputs, completion ratio,
and model calls plus input/output/cache-read token totals. It
never returns the platform subject, requester id, email, prompt, answer,
conversation id, source activity, or tool arguments. Email-shaped display
values are replaced by the opaque fallback label.
This route has the same fail-closed Kaizen App Admin gate, but is kept separate
from the anonymous aggregate contract so each disclosure can emit
admin.usage.members.viewed. The audit payload contains only the selected
window, returned member count, and availability. The browser does not poll the
member endpoint continuously; the response has the same 60-second cache as the
selected window.
A2A
GET /api/ops/a2a
POST /api/ops/a2a/validate
PUT /api/ops/a2a/flags/{flag}
PUT /api/ops/a2a/public-base-url
PUT /api/ops/a2a/shared-secret
PUT /api/ops/a2a/inbound-agents
Run validate before relying on a configuration change. A2A is a proof of
concept intended for isolated deployments.
GET /api/ops/a2a returns a versions map keyed by the settings A2A owns. Each
entry is the config store's current version for that key, or null while the
key still carries its deployment value. The mappings, public address, and
capability secret are internal selectors omitted from the general settings list,
and this map is the only read path for their versions. Send the value for the
key you are writing as expected_version; a stale value returns
409 version_conflict, and a successful write advances the version the next
status read reports.
What the ops surface is not
It configures the deployment. It is not a window into member content — no ops route returns another member's chats, documents, or tasks.
Holding the admin role grants configuration authority, not read access. If a proposed ops endpoint would return member content, that is a design smell worth resolving before it ships.