Oxelone Docs

Search docs and API

Find a guide, a section of one, or an API operation by its name.

Open console (opens in a new tab)

API reference Resources

Policies

Policies: authoring, lifecycle, hits and simulation.

35 operations

List decisions

GET/decisions

Decisions newest first, each with the engine runs that fed it. Page with after, passing the previous page's next.

Query parameters

windowstring · null

1h, 24h, 7d or 30d. Defaults to 24h.

policystring · null

A policy id, the workspace's own or a provided one.

outcomestring · null

blocked | alerted | justified | undetermined | passed.

fstring · null

The filter expression, e.g. all;outcome~in~blocked;action~in~redact.

Joined by all, each segment field~in~values with values separated by commas. Fields: outcome, policy, action (block, redact, ask, connector_action), engine, machine, inspection (not_inspected: content not inspected because of its size). A field or value this list does not have is a 400 naming it.

qstring · null

Free text over a reference, a user, a hostname and, on a connector action, its record and connection.

referencestring · null

One decision by its reference, a filter of its own. A malformed reference is a 400. With no window named, the window is unbounded.

include_removedboolean · null

Keep rows whose machine or connection was removed. Default false; a read scoped by interaction or reference ignores it.

interactionstring · null

An interaction id: every decision about that one interaction, whatever its outcome. With no window named, the window is unbounded.

afterstring · null

The next of the previous page.

limitinteger · null

Clamped to 1–200; default 50.

Response200

A page of decisions with their runs

decisionsDecisionTrace[]required
actionsstring[]required

The verbs the deciding policy version lists, wire names, in its order. ["connector_action"] on an action row. Empty for a caller holding only alerts:read.

atstringrequired
decided_bystringrequired

inline | policy | engine | connector (kind=action rows): who decided.

idstringrequired
kindstringrequired

decision for a decision about an interaction; action for something a rule or a person did through a connection.

outcomestringrequired
totalintegerrequired

Every decision the window and filters match, whatever page this is.

nextstring · null

Errors

400

A window, policy, outcome, facet, reference or cursor this endpoint does not accept

401

No valid session

403

Caller lacks both policies:read and alerts:read in this workspace

One decision by reference

GET/decisions/by-reference/{reference}

One decision by the reference a person was shown when their request was stopped. A malformed reference is a 400 naming the format.

Path parameters

referencestringrequired

Response200

The decision the reference names

decisionDecisionTracerequired
actionsstring[]required

The verbs the deciding policy version lists, wire names, in its order. ["connector_action"] on an action row. Empty for a caller holding only alerts:read.

atstringrequired
decided_bystringrequired

inline | policy | engine | connector (kind=action rows): who decided.

idstringrequired
kindstringrequired

decision for a decision about an interaction; action for something a rule or a person did through a connection.

outcomestringrequired
issueDecisionIssueRef · null
idstringrequired
statusstringrequired

open | acknowledged | resolved | suppressed.

titlestringrequired

Errors

400

Not a well-formed reference; the message names the format

401

No valid session

403

Caller lacks both policies:read and alerts:read in this workspace

404

No decision with that reference in this workspace

Decision counts

GET/decisions/kpis

The window's decision counts, and the 95th-percentile engine time in milliseconds.

Query parameters

windowstring · null

1h, 24h, 7d or 30d. Defaults to 24h.

include_removedboolean · null

Count rows whose machine or connection was removed. Default false.

Response200

Counts over the window

blockedintegerrequired
decisionsintegerrequired

Decisions and connector actions in the window.

justifiedintegerrequired
redactedintegerrequired

Redactions that happened: enforcing matches on a policy version that lists Redact and no Block (which would have won).

undeterminedintegerrequired
windowstringrequired
p95_msnumber · null

Weighted p95 of the engine runs that served a policy; workspace-wide.

Errors

400

The window is not one of 1h, 24h, 7d, 30d

401

No valid session

403

Caller lacks policies:read in this workspace

Decisions per policy

GET/decisions/summary

Per policy: decisions by outcome over the window, and why undetermined.

Query parameters

windowstring · null

1h, 24h, 7d or 30d. Defaults to 24h.

Response200

Decisions per policy over the window

bucket_startsstring[]required

Twelve RFC 3339 bucket starts, oldest first.

policiesPolicyDecisionStat[]required

Every policy with a decision in the window. Passed decisions are not kept except where the late pass settled one.

by_outcomeDecisionOutcomeCount[]required
decisionsintegerrequired
modestringrequired

draft | monitor | enforce — the policy's mode for this workspace now.

namestringrequired
policy_idstringrequired
providedbooleanrequired

true for a policy provided by Oxelone rather than written by the workspace.

undetermined_reasonsUndeterminedReasonCount[]required
countintegerrequired
reasonstringrequired
windowstringrequired

Errors

400

The window is not one of 1h, 24h, 7d, 30d

401

No valid session

403

Caller lacks policies:read in this workspace

One decision

GET/decisions/{id}

One decision or connector action by its id, of any age, removed or not. An unknown id, a malformed one and another workspace's are all 404.

Path parameters

idstringrequired

Response200

The decision, its runs and the issue it joined

decisionDecisionTracerequired
actionsstring[]required

The verbs the deciding policy version lists, wire names, in its order. ["connector_action"] on an action row. Empty for a caller holding only alerts:read.

atstringrequired
decided_bystringrequired

inline | policy | engine | connector (kind=action rows): who decided.

idstringrequired
kindstringrequired

decision for a decision about an interaction; action for something a rule or a person did through a connection.

outcomestringrequired
issueDecisionIssueRef · null
idstringrequired
statusstringrequired

open | acknowledged | resolved | suppressed.

titlestringrequired

Errors

401

No valid session

403

Caller lacks both policies:read and alerts:read in this workspace

404

No decision with that id in this workspace

What each hook tool can do with each action

GET/hook-capabilities

policies:read: it describes the authoring surface and reveals nothing a policy reader may not already see — the same gate as the capabilities document.

Response200

Each hook tool's block, native ask and companion ask per action

if_no_companionstringrequired

What an Ask at a hook does when no companion is running, as one sentence.

kindsHookKindWord[]required

The eight action kinds with their words, in picker order.

idstringrequired
labelstringrequired

The display name, e.g. Shell command, Tool call.

toolsHookTool[]required

One per tool whose vendor documents blocking hooks, in the registry's order.

actionsobjectrequired

Per action kind; a kind absent here has no hook on this tool.

namestringrequired

The registry's display name (Claude Code, Devin Desktop).

on_timeoutstringrequired

What the tool does when its hook times out: open or closed.

slugstringrequired

The registry slug (claude_code).

bypass_signalBypassSignal · null
timeout_secsinteger · null

The hook timeout we write into the tool's config, or null where it has no field (Windsurf: its own limit is unmeasured).

versionintegerrequired

The capability document's version (hook_capabilities.json's version).

Errors

401

No valid session

403

Caller lacks policies:read in this workspace

404

No such workspace, or the caller is not a member

List policies

GET/policies

Every policy in this workspace, at its current version, or with ?connection= only the rules bound to that connection.

Query parameters

connectionstring

A connection id: only that connection's rules, in precedence order.

An id that is not a connection in this workspace, cannot be parsed, or was removed is a 404, never an empty list.

Response200

Policies in this workspace

groupsGroup[]required

Every policy group this workspace sees, those provided by Oxelone and its own, of every type, in reading order. A policy row's group_id names the group it is in, null when it is in none.

descriptionstringrequired
enabledbooleanrequired

On (true) or Off. Off pauses every member.

idstringrequired
member_idsstring[]required

The members, in member order.

namestringrequired
removedbooleanrequired

A provided group this workspace removed (listed with the removed policies).

hit_countsPolicyHitCount[]required

How many decisions each policy has ever produced — a filter match, whatever the outcome or the state — with its trailing seven days, day by day. One entry per policy that has any; a policy with none is absent.

dailyinteger[]required

Hits per UTC day, oldest first, today last, zero-filled: always seven entries, all zeros for a policy last hit before the window.

policy_idstringrequired
recentintegerrequired

Hits in the trailing seven UTC days: the sum of daily. Not the same figure as last_30d on GET /policies/{id}/hits, which is a rolling 30 days.

totalintegerrequired

Every hit this policy has ever had.

policiesobject[]required

Errors

401

No valid session

403

Caller lacks policies:read in this workspace

404

No such workspace, no such connection, or the caller is not a member

Create a policy

POST/policies

The policy starts Disabled (draft) unless mode says otherwise. enforce needs policies:publish, as /mode does; monitor and enforce are checked as enabling a Disabled policy is, and monitor needs a policy that can hold something back. A policy that starts in Monitor or Enabled ships at once, and the reply carries what that publish did under publish — null for a Disabled policy — beside the policy's own fields, mode among them.

Request bodyCreatePolicyInput

bodyobjectrequired
modestring · null

One of draft, monitor, enforce. Absent is draft, as every create was before this field existed.

Response201

Policy created: the policy as stored, plus holds_back and publish (the auto-publish's {hash, warnings, halted}, null for a draft)

Errors

400

Policy body is malformed or fails validation, an unknown mode, or Monitor on a policy that holds nothing back

401

No valid session

403

Caller lacks policies:write in this workspace, or policies:publish for enforce

404

No such workspace, or the caller is not a member

Compile and publish policies

POST/policies/compile

Compiles every policy that is not Disabled, together with the PII & Secrets rules and the workspace's catalogued services, and publishes the result as what every machine in the workspace runs next. While enforcement is halted, every policy is published as Monitor; the stored states are untouched.

Response201

Compiled and published as the workspace's current bundle

haltedbooleanrequired

Whether this publish happened while enforcement is halted, and therefore enforces nothing whatever the policy list says.

hashstringrequired
warningsCompileWarning[]required

Policies that compiled but cannot fire in this workspace as it is configured — almost always because of which backend an engine is set to. Empty is the normal case.

A warning and not a refusal: such a policy is undetermined rather than invalid, and refusing the compile would let switching a backend brick publishing for a whole workspace. Silence was the other option, and it is the worse one — an operator would leave a policy in enforce believing it covers something nothing is looking for.

enginestringrequired
messagestringrequired

The same thing in a sentence, for an operator who is not going to look the reason code up.

policy_idstringrequired
policy_namestringrequired

The policy's own name, so an operator recognises it in the list. The id is the handle they act on.

reasonstringrequired

Stable and machine-readable: label_not_emittable, no_backend, engine_has_no_runner, or engine_unknown. no_backend is the one you can fix, by choosing a backend for the engine; engine_has_no_runner cannot be fixed by any setting.

labelstring · null

The canonical label the condition binds, when the warning is about one.

Errors

401

No valid session

403

Caller lacks policies:publish in this workspace

404

No such workspace, or the caller is not a member

Enforcement state

GET/policies/enforcement

What is enforcing in this workspace, and on how many machines: whether enforcement is halted, and how far the current publish has reached.

Response200

Halt state and bundle rollout

machinesintegerrequired
never_reportedintegerrequired
on_currentintegerrequired
propagation_secondsintegerrequired

How long a machine may take to notice a change, in seconds: the interval at which this workspace's machines check in. A halt or a publish is not instant; alerts can keep arriving until then.

staleintegerrequired
bundle_hashstring · null

The hash of what this workspace has published, or null if nothing has been. While it is null a machine has no site catalog, captures nothing, and reports "outcome": "no catalog".

haltHalt · null
halted_atstringrequired
reasonstringrequired

The reason given when enforcement was halted; always present.

Errors

401

No valid session

403

Caller lacks policies:read in this workspace

404

No such workspace, or the caller is not a member

Halt enforcement

POST/policies/enforcement/halt

Stops enforcing everything in this workspace without changing a single policy: every policy runs as Monitor, and alerts are still raised. Takes effect at once — the policies are republished in the same request, and if that fails the whole request fails, so a success means the machines are being told. Needs policies:publish and a reason, which is recorded.

Request bodyHaltRequest

reasonstringrequired

Why enforcement is being stopped. Must not be blank.

Response200

Enforcement halted and a bundle republished

machinesintegerrequired
never_reportedintegerrequired
on_currentintegerrequired
propagation_secondsintegerrequired

How long a machine may take to notice a change, in seconds: the interval at which this workspace's machines check in. A halt or a publish is not instant; alerts can keep arriving until then.

staleintegerrequired
bundle_hashstring · null

The hash of what this workspace has published, or null if nothing has been. While it is null a machine has no site catalog, captures nothing, and reports "outcome": "no catalog".

haltHalt · null
halted_atstringrequired
reasonstringrequired

The reason given when enforcement was halted; always present.

Errors

400

No reason was given

401

No valid session

403

Caller lacks policies:publish in this workspace

404

No such workspace, or the caller is not a member

Resume enforcement

POST/policies/enforcement/resume

Lets enforcement resume after a halt. Every policy returns to whatever its state already said, because the halt never changed it.

Response200

Enforcement resumed and a bundle republished

machinesintegerrequired
never_reportedintegerrequired
on_currentintegerrequired
propagation_secondsintegerrequired

How long a machine may take to notice a change, in seconds: the interval at which this workspace's machines check in. A halt or a publish is not instant; alerts can keep arriving until then.

staleintegerrequired
bundle_hashstring · null

The hash of what this workspace has published, or null if nothing has been. While it is null a machine has no site catalog, captures nothing, and reports "outcome": "no catalog".

haltHalt · null
halted_atstringrequired
reasonstringrequired

The reason given when enforcement was halted; always present.

Errors

401

No valid session

403

Caller lacks policies:publish in this workspace

404

No such workspace, or the caller is not a member

A tab's top level, in order

GET/policies/layout

Query parameters

subjectstringrequired

The tab: a policy type's wire value — prompt, file_artifact, hook, connector_event, …

Response200

The tab's groups and policies in no group, in order

itemsLayoutItem[]required

The tab's top level, first first: every group on it, and every policy in no group.

idstringrequired

The group's id, or the policy's (own or provided).

kindstringrequired

group or policy.

Errors

400

Unknown policy type

401

No valid session

403

Caller lacks policies:read in this workspace

404

No such workspace, or the caller is not a member

Replace a tab's top-level order

PUT/policies/layout

Refuses an item that is not on the tab — another workspace's, another type's, or a policy that is in a group (it moves within its group) — and a list that is not the tab's whole top level (409: it changed since it was read, the rule PUT /policies/order has for a partial list). Reading order only, like that route; it republishes because the bundle's policy order follows precedence.

Request bodySetLayoutRequest

itemsLayoutItem[]required

Every item GET answers for this tab, in the new order. A replacement: an item left out is a stale list (409), not a removal.

idstringrequired

The group's id, or the policy's (own or provided).

kindstringrequired

group or policy.

subjectstringrequired

The tab, as GET's subject.

Response200

The layout as stored

itemsLayoutItem[]required

The tab's top level, first first: every group on it, and every policy in no group.

idstringrequired

The group's id, or the policy's (own or provided).

kindstringrequired

group or policy.

Errors

400

Unknown type or kind, a malformed or repeated id, an id that is not this workspace's, an item of another type, or a policy that is in a group

401

No valid session

403

Caller lacks policies:write in this workspace

404

No such workspace, or the caller is not a member

409

The list is not the tab's whole top level: it changed since it was read

Set the state of many policies

PUT/policies/modes

One transaction and one publish. Each id is checked as POST /policies/{id}/mode checks it — leaving Disabled re-validates against this workspace's engines and connections, and a connector's rule is refused because it is switched per connection — and a refused id is reported and left as it was while the rest are written together. A policy whose group is Off has its stored state written like any other; it stays paused until its group is On.

Needs policies:write, and policies:publish as well when the mode is enforce.

Request bodySetModesRequest

idsstring[]required

Policy ids, the workspace's own and provided ones alike.

modestringrequired

One of draft, monitor, enforce.

Response200

Each id's outcome, and the one publish

kept_enabledintegerrequired

Monitor where it applies: how many of the ids asked for Monitor are Enabled instead (changed to it, or already in it), because nothing in them changes anything. 0 for any other mode.

resultsModeResult[]required

One entry per id sent, in the order sent.

idstringrequired
outcomestringrequired

changed, unchanged (it already had that mode), refused (see refusal; nothing was written for it), or not_found.

modestring · null

The mode it is in after this change — enforce where monitor was asked for and the policy holds nothing back — or null when it was refused or not found.

refusalstring · null

Why it was refused, as a sentence, or null.

publishCompileResponse · null
haltedbooleanrequired

Whether this publish happened while enforcement is halted, and therefore enforces nothing whatever the policy list says.

hashstringrequired
warningsCompileWarning[]required

Policies that compiled but cannot fire in this workspace as it is configured — almost always because of which backend an engine is set to. Empty is the normal case.

A warning and not a refusal: such a policy is undetermined rather than invalid, and refusing the compile would let switching a backend brick publishing for a whole workspace. Silence was the other option, and it is the worse one — an operator would leave a policy in enforce believing it covers something nothing is looking for.

Errors

400

Unknown mode, a malformed or repeated id, or more than 500 ids

401

No valid session

403

Caller lacks policies:write, or policies:publish for enforce

404

No such workspace, or the caller is not a member

Reorder policies

PUT/policies/order

Sets the order one policy type's list is read in, and nothing else. It does not make the first matching policy win: every policy is evaluated and every match raises its own alert.

The list must name every policy of that type in this workspace; a partial list is refused with a 400 that gives the expected count. Needs policies:write. Reordering publishes nothing and reaches no machine.

Request bodySetOrderRequest

idsstring[]required

Every policy of that type in this workspace, in the order they should appear.

subjectstringrequired

The policy type this order is within — one of prompt, file_artifact, asset, connector_event, egress.

Required rather than inferred from the ids, and that is the point of the field: precedence is only meaningful within a type, because ordering a prompt policy against a file-artifact one answers no question anybody asks. Naming it lets the route refuse a list that mixes two, which is a caller bug that would otherwise be stored and rendered as an order.

Response200

Order stored

reorderedintegerrequired

How many policies moved: the number of ids sent, on success. A partial list is refused, never applied in part.

Errors

400

Unknown policy type, an id that is not this workspace's, an id of another type, or an incomplete list

401

No valid session

403

Caller lacks policies:write in this workspace

404

No such workspace, or the caller is not a member

List removed policies

GET/policies/removed

The policies provided by Oxelone that this workspace removed. Each can be brought back with POST /policies/{id}/restore.

Response200

The policies provided by Oxelone that this workspace removed, restorable

policiesobject[]required

Errors

403

Caller lacks policies:read in this workspace

Simulate one call against this workspace's policies

POST/policies/simulate

Request bodySimulateRequest

toolstringrequired

The tool's registry slug (claude_code). Required for hook; for prompt it names the tool whose vendor host the request goes to.

triggerstringrequired

hook — a tool's hook call (action says which) — or prompt, a Network prompt as the network path sees it. A prompt a hook saw is trigger: "hook", action: "prompt".

actionstring · null

The action kind (shell, file_read, …). Required for hook.

companion_presentboolean

A companion is running in the person's session. Default true.

contentboolean

The machine observes content. false simulates a metadata-only machine: every content fact reads unknown. Default true.

draftPolicyInput · null

The fields of a policy a caller writes: name, subject_kind, condition, actions, fail_mode, latency_budget_ms. id and version are assigned by the server, and a policy's state is changed only through its mode route, which needs policies:publish.

bodyobjectrequired
inputSimulateInput

The facts of the call that fit its kind.

commandstring · null
cwdstring · null

The working directory, as the agent normalises it (~/src/app).

mcp_serverstring · null
mcp_toolstring · null
modelstring · null
pathstring · null
profile_idstring · null

The enrollment profile to simulate as; null is a machine with no profile.

skip_permissionsboolean

The tool is set to skip permissions: the simulated call carries the tool's bypass value, where it has one.

Response200

The winner, the route, and every policy of the trigger with its result

alsoAlso[]required

The non-enforcing actions of every matched policy: what is raised besides the decision.

verbstringrequired

alert or webhook.

notifyboolean

An Alert that also tells the person in the moment (Notify).

severitystring · null
network_alsoSimulatedPolicy[]required

For a prompt at a hook: the Network policies checked there, in the same shape.

decisionstringrequired

The policy's own decision: allow, ask, block (or redact for a Network policy).

idstringrequired
namestringrequired
orderintegerrequired

Its place in the list, from 1.

resultstringrequired

matched, no_match, other_action, out_of_scope, disabled, monitor or undetermined.

sentencestringrequired

Why, in one line.

policiesSimulatedPolicy[]required

Every policy of the trigger — Hook policies of this kind, and for a prompt every Network policy — matched or not, Disabled, Monitor and out of scope included, each with why.

decisionstringrequired

The policy's own decision: allow, ask, block (or redact for a Network policy).

idstringrequired
namestringrequired
orderintegerrequired

Its place in the list, from 1.

resultstringrequired

matched, no_match, other_action, out_of_scope, disabled, monitor or undetermined.

sentencestringrequired

Why, in one line.

winnerWinnerrequired
decisionstringrequired

allow, ask or block, the strictest of the matched policies winning, or undetermined when the outcome waits on an engine result, which a simulation does not run. For an Ask with no companion running this is still ask; what happens then is if_no_companion's sentence.

policiesPolicyRef[]required

The policies that decided it: every merged Ask, or the blocking ones.

require_reasonbooleanrequired
messagestring · null

The merged question, as the person would read it; null for Oxelone's default wording.

if_no_companionstring · null

What happens when no companion is running, as a sentence; null unless the Ask would go to the companion.

if_unansweredstring · null

What happens when nobody answers, as a sentence; null when nobody would be asked.

routeRoute · null
throughstringrequired

native or companion.

whystringrequired

Errors

400

Unknown trigger, tool or action, or a draft that would not save

401

No valid session

403

Caller lacks policies:read in this workspace

404

No such workspace, or the caller is not a member

Preview an AI tool policy

POST/policies/tool-config-preview

How many of this workspace's machines an unsaved AI tool policy would match now.

Request bodyToolConfigPreviewRequest

policyobjectrequired

The unsaved policy body, in the shape POST /policies takes: a Host policy about an AI tool, triggered while present.

Response200

by_toolPreviewByTool[]required
nintegerrequired
toolstringrequired
fix_capableintegerrequired

Matched machines where the agent can fix the setting itself, in a tool the policy matched.

machines_matchedintegerrequired
machines_reportingintegerrequired
partialbooleanrequired

More than 5,000 reads: the counts are over the newest 5,000.

samplePreviewSample[]required
hostnamestringrequired
machine_idstringrequired
toolstringrequired
evidencestring · null

The first item the filter matched (a rule, an MCP server, a plugin), when it matched one.

Errors

400

Not a Host policy about an AI tool, triggered while present

403

Caller lacks policies:write or machines:read in this workspace

Validate a policy body

POST/policies/validate

Checks a policy body as saving it would, and says whether it could be enabled and, if not, why — without storing anything. Needs policies:write; it does not need policies:publish, so an author learns why a rule cannot be enabled before asking someone who can enable it.

Request bodyPolicyInput

bodyobjectrequired

Response200

The verdict, whichever way it went

can_armbooleanrequired

Whether this body could be armed — moved out of draft — as things stand in this workspace right now.

enforcement_barredbooleanrequired

Whether the refusal is about enforcing — an engine not accurate enough to block or redact on — rather than something an unfinished policy has not got round to yet. can_arm: false alone does not say which. False whenever there is no refusal.

okbooleanrequired

Whether this body can be saved as a draft. False only for something storage itself cannot hold — a body that does not match the model, or a pattern that does not compile.

warningsPolicyWarning[]required

What publishing will warn about in this body, never a refusal: scope_names_missing_profile for a profile deleted since it was named, targets_hook_actions for a Network policy written against hook:// or HOOK. Empty when the body did not parse.

codestringrequired

scope_names_missing_profile or targets_hook_actions.

messagestringrequired

A sentence for the policy's author, meant to be shown as it is.

arming_refusalstring · null

Why this body could not be enabled, or null if it could. Show it as it is: where an engine's accuracy is the reason, it names the measured false-positive rate and the backend to choose instead.

limitationsLimitation[]

What this workspace's fleet will not do for this body, even though nothing refuses it — for example, a category no live machine scans for.

Never a refusal: it does not change ok or can_arm. Absent when empty.

codestringrequired
messagestringrequired
refusalstring · null

Why not, in the server's own words, or null.

Errors

400

The body is not a JSON object at all

401

No valid session

403

Caller lacks policies:write in this workspace

404

No such workspace, or the caller is not a member

Publish a new version of an existing policy

PUT/policies/{id}

The live mode is preserved from the existing policy, never taken from the request body — see the PolicyInput doc comment. Changing mode is exclusively POST .../mode's job.

Path parameters

idstringrequired

Request bodyPolicyInput

bodyobjectrequired

Response200

New version published, and auto-published unless the policy is Disabled

policyobjectrequired
publishCompileResponse · null
haltedbooleanrequired

Whether this publish happened while enforcement is halted, and therefore enforces nothing whatever the policy list says.

hashstringrequired
warningsCompileWarning[]required

Policies that compiled but cannot fire in this workspace as it is configured — almost always because of which backend an engine is set to. Empty is the normal case.

A warning and not a refusal: such a policy is undetermined rather than invalid, and refusing the compile would let switching a backend brick publishing for a whole workspace. Silence was the other option, and it is the worse one — an operator would leave a policy in enforce believing it covers something nothing is looking for.

Errors

400

Policy body is malformed or fails validation, or an ENABLED policy's edit would leave it unarmable

401

No valid session

403

Caller lacks policies:write in this workspace

404

No such policy in this workspace

Delete a policy

DELETE/policies/{id}

The policy leaves the list and stops running on every machine; the policies are republished in the same request. Its version history is kept, so alerts it raised still name the exact rule that fired.

policies:write deletes a Disabled or Monitor policy; deleting an Enabled one also needs policies:publish, because it stops live enforcement. An unknown id, or one in another workspace, is a 404.

Path parameters

idstringrequired

Response200

Policy soft-deleted and the bundle republished in the same request

haltedbooleanrequired

Whether this publish happened while enforcement is halted, and therefore enforces nothing whatever the policy list says.

hashstringrequired
warningsCompileWarning[]required

Policies that compiled but cannot fire in this workspace as it is configured — almost always because of which backend an engine is set to. Empty is the normal case.

A warning and not a refusal: such a policy is undetermined rather than invalid, and refusing the compile would let switching a backend brick publishing for a whole workspace. Silence was the other option, and it is the worse one — an operator would leave a policy in enforce believing it covers something nothing is looking for.

enginestringrequired
messagestringrequired

The same thing in a sentence, for an operator who is not going to look the reason code up.

policy_idstringrequired
policy_namestringrequired

The policy's own name, so an operator recognises it in the list. The id is the handle they act on.

reasonstringrequired

Stable and machine-readable: label_not_emittable, no_backend, engine_has_no_runner, or engine_unknown. no_backend is the one you can fix, by choosing a backend for the engine; engine_has_no_runner cannot be fixed by any setting.

labelstring · null

The canonical label the condition binds, when the warning is about one.

Errors

401

No valid session

403

Caller lacks the grant this delete requires — policies:write, or policies:publish for an enforcing policy

404

No such policy in this workspace

One policy's activity

GET/policies/{id}/activity

One policy's decisions over a window, with the engines and tools behind them. Works for the workspace's own policies and provided ones.

Path parameters

idstringrequired

Query parameters

windowstring · null

24h, 7d or 30d. Defaults to 30d.

Response200

The policy's decisions, engines and tools over the window

alertedintegerrequired
blockedintegerrequired
bucket_startsstring[]required

Thirty RFC 3339 bucket starts, oldest first.

decisionsintegerrequired
enginesActivityEngine[]required
engine_idstringrequired
errorsintegerrequired
runsintegerrequired
p95_msnumber · null
machinesintegerrequired
seriesActivityOutcomeSeries[]required

One per outcome present.

countsinteger[]required

Aligned with bucket_starts.

outcomestringrequired
toolsActivityTool[]required

The top three tools.

sharenumberrequired

0–1, of decisions.

toolstringrequired
undeterminedintegerrequired
windowstringrequired
p95_msnumber · null

Errors

400

The window is not one of 24h, 7d, 30d

401

No valid session

403

Caller lacks policies:read in this workspace

404

No such policy in this workspace, and no such provided policy

Duplicate a provided policy

POST/policies/{id}/duplicate

Copies a policy provided by Oxelone into one this workspace owns and can edit. The copy starts Disabled. Needs policies:write.

Path parameters

idstringrequired

Request bodyDuplicateRequest

namestring · null

The copy's name; "Copy of <vendor name>" when absent.

Response201

A policy this workspace owns, Disabled, with the provided policy's content

Errors

403

Caller lacks policies:write in this workspace

404

No such policy provided by Oxelone

A policy's hit counts

GET/policies/{id}/hits

How often this policy's filter has matched: every decision it produced, in every state and with every outcome, in total and over the trailing 30 days. Broader than the preview on purpose: the preview counts only Monitor, while this answers whether the rule is doing anything at all.

Path parameters

idstringrequired

Response200

Total decisions, and the trailing 30 days

last_30dintegerrequired
totalintegerrequired

Errors

401

No valid session

403

Caller lacks policies:read in this workspace

404

No such policy in this workspace

Set a policy's state

POST/policies/{id}/mode

Moves a policy between Disabled (draft), Monitor (monitor) and Enabled (enforce), and republishes in the same request. Needs policies:write; reaching enforce also needs policies:publish. Every change is recorded in the audit log, so you can later tell whether a policy was enforcing when an alert was raised.

Path parameters

idstringrequired

Request bodySetModeRequest

modestringrequired

One of draft, monitor, enforce.

Response200

Mode changed, and the bundle republished in the same request

policyobjectrequired
publishCompileResponse · null
haltedbooleanrequired

Whether this publish happened while enforcement is halted, and therefore enforces nothing whatever the policy list says.

hashstringrequired
warningsCompileWarning[]required

Policies that compiled but cannot fire in this workspace as it is configured — almost always because of which backend an engine is set to. Empty is the normal case.

A warning and not a refusal: such a policy is undetermined rather than invalid, and refusing the compile would let switching a backend brick publishing for a whole workspace. Silence was the other option, and it is the worse one — an operator would leave a policy in enforce believing it covers something nothing is looking for.

Errors

400

Unknown mode

401

No valid session

403

Caller lacks the grant this transition requires

404

No such policy in this workspace

Preview a policy

GET/policies/{id}/preview

What this policy would have done had it been Enabled, from what it matched while in Monitor. Every count is scoped to Monitor: a decision made while the policy was already Enabled is not evidence about enabling it. Needs policies:read.

An empty answer is not a safe answer: a policy put in Monitor minutes ago and one that genuinely matches nothing produce identical counts, which is what first_at tells apart.

Path parameters

idstringrequired

Query parameters

daysinteger · null

Whole days, 1–90. Defaults to 7. 90 days is also the longest a workspace can keep engine runs.

Response200

What arming this policy would have changed

daysintegerrequired

The window actually used, in whole days, after clamping.

machinesintegerrequired

Distinct machines among the matches.

matchedintegerrequired

Interactions this policy matched while watching.

pausedbooleanrequired

Whether this policy's group is Off: it reads as Disabled and runs nowhere, so enabling it changes nothing until its group is On. The counts are still what it did while it ran.

servicesServiceHits[]required
hitsintegerrequired
servicestringrequired
undeterminedintegerrequired

Interactions the policy could not decide, because an engine returned no verdict. Under a policy that fails closed, each of these becomes a block once the policy is Enabled.

undetermined_would_blockintegerrequired

How many of those undetermined interactions would become blocks: equal to undetermined when this policy fails closed, and zero when it fails open.

versionintegerrequired

The version the counts are being read for.

would_have_stoppedintegerrequired

How many of those it would have stopped.

Equal to matched when the policy binds an inline enforcing action, and zero when it does not — which is the fact a promote button most needs to be able to say out loud. An alert-only policy in enforce alerts, exactly as it did in monitor; promoting it changes nothing about what anybody can do, and a preview that reported its match count as a blast radius would be arguing for a change that has none.

current_version_age_hoursinteger · null

How long the version being previewed has existed, in whole hours, or null if that is not knowable.

The counts are not filtered by version, so when this is shorter than the preview window, some of the matches belong to an earlier version of the policy.

first_atstring · null

The earliest decision in the window, or null if there were none.

Errors

400

The window is out of range, or the id is reserved

401

No valid session

403

Caller lacks policies:read in this workspace

404

No such policy in this workspace, or a provided policy it cannot preview

Restore a removed policy

POST/policies/{id}/restore

Brings back a policy provided by Oxelone that this workspace removed, in the state it had, and republishes. Needs policies:write; restoring one that was Enabled also needs policies:publish, because it starts enforcing again.

Path parameters

idstringrequired

Response200

Back in this workspace's list, in the state it had

policyobjectrequired
publishCompileResponse · null
haltedbooleanrequired

Whether this publish happened while enforcement is halted, and therefore enforces nothing whatever the policy list says.

hashstringrequired
warningsCompileWarning[]required

Policies that compiled but cannot fire in this workspace as it is configured — almost always because of which backend an engine is set to. Empty is the normal case.

A warning and not a refusal: such a policy is undetermined rather than invalid, and refusing the compile would let switching a backend brick publishing for a whole workspace. Silence was the other option, and it is the worse one — an operator would leave a policy in enforce believing it covers something nothing is looking for.

Errors

403

Caller lacks policies:write in this workspace

404

Not a policy provided by Oxelone that this workspace removed

What a policy type can do

GET/policy-capabilities

For one policy type, every filter field, comparison, engine, input and response a policy may use in this workspace, with how many machines can act on a filter field or a response today.

Query parameters

subjectstring · null

The policy type: prompt, file_artifact, asset, connector_event, or egress. Required; missing or unknown is a 400.

connectionstring · null

Which connection the catalogue is for. Meaningful only with subject=connector_event; ignored for every other type.

connectorstring · null

Which connector the catalogue is for.

The platform document's narrowing, and the one it needs: a vendor policy is written for one connector (vendor_policies.connector), and without this the document lists every live connector's record kinds in one list. On a workspace document the connection already names its connector, so this is only a cross-check: sending both and disagreeing is a 400, and sending it alone is ignored.

actionstring · null

The Hook trigger's action kind (shell, file_read, …): narrows predicates and actions to what a policy on that action offers. Meaningful only with subject=hook; ignored elsewhere, like connection. An unknown word is a 400 that names the eight.

Response200

What this workspace can do with this policy type

actionsActionCapability[]required
availablebooleanrequired

Whether Oxelone can run this verb in this workspace: a connector exists for it, the subject carries a live request to act on, or a destination is stored. It does not depend on how many machines are enrolled.

channelstringrequired

Where the verb runs, derived from the verb: inline for an enforcing verb, connector for a connector verb, otherwise server_async.

config_fieldsstring[]required

The configuration keys this verb takes, in display order — for ask, message and require_reason.

machines_coveredintegerrequired

How many of this workspace's machines this verb would act on today.

Zero is a normal answer. It is the coverage strip's sentence — fires on 0 of your machines today — and not a reason to hide a verb; an author can write a real policy before enrolling anything, and that is the case this field exists for.

Per verb rather than one number for the document, because the verbs genuinely differ and the differences are the interesting part: block counts machines whose capture sits in the request path, redact counts the narrower set whose capture reads a body at all, and alert counts every live machine because a server-side alarm needs nothing from the endpoint. A single count would be wrong for redact on a metadata fleet, which is the one sentence the whole coverage strip exists to say.

verbstringrequired
unavailable_reasonstring · null

Why this verb is unavailable, as a full sentence. Present exactly when available is false.

enginesEngineCondition[]required

What each engine can actually be asked about, as the engine declares it.

availabilityEngineAvailabilityrequired

Whether this engine will answer in this workspace, the same answer GET /engines gives. An unavailable engine is still listed: a row may be written over it, and the editor warns beside the row.

display_namestringrequired

The engine's display name, as the engine list shows it.

enginestringrequired

The engine's id, as a policy's engine filter names it.

fieldsEngineField[]required

The fields of the engine's own output a filter may read. Empty until the engine publishes them.

judgesJudgeCondition[]required

Only for llm-judge, and empty for every other engine.

labelsLabel[]required

The label vocabulary, narrowed to the backend this workspace selected. An unemittable label is listed and flagged rather than dropped: a policy written against a build that could emit it must still render, and the editor must still not offer it as a new condition.

host_categoriesHostCategory[]required

The categories a Host policy may pick, for file_artifact; empty for every other subject. A policy picks at most one; none means every category.

eventsstring[]required

The artifact events a Host policy over this category may be triggered by, in the File Events page's own order.

Not the same list for every category — HostCategory:: offered_events withholds content_changed from a category nothing hashes, and an AI Tool is an installation rather than a file. A picker that offered it anyway would let an author arm a trigger that can never fire, which is the placebo this whole document exists to prevent.

idstringrequired
labelstringrequired
content_refusalstring · null

Why a filter over this category's content is refused, or absent when it is not refused — the domain own sentence, shown verbatim.

This is what keeps the narrowing from being unexplained. Switching a policy to Model weights takes the content filters out of the picker, and a picker that quietly gets shorter reads as a bug. The editor prints this beside the count it dropped.

verbsCategoryVerb[]

Verbs this category alone offers, and on which triggers — today, Fix on AI tool, while present. Absent on every other category.

inputsInput[]required

What may be given to an engine under this trigger — the text a policy can look at, as opposed to the facts in predicates. In picker order; empty for a subject with no editor.

enginesstring[]required

The engines that will answer a filter written under this input. An engine that reads its subject by reference (rather than its text) is listed only under file_name on Host and request on Network.

host_categoriesstring[]required

The Host categories that allow it, as category ids. Empty means every one — a file's name and location are known whatever the file is. file_contents names the five categories that carry text; the three opaque ones and AI Dependency (read as entries rather than text) are absent. A Host policy that has picked no category may read contents. Empty on a Network document; always present.

idstringrequired

The value a row's input carries: prompt | attachment | request | file_contents | file_name.

interaction_kindsstring[]required

The sub-category choices under which this input is offered, where all means a policy that has not picked one. Empty means every choice, which is what the prompt and the whole request answer; only the attachment narrows, to ["all", "attachment"]. Empty on a Host document; always present.

labelstringrequired

The display name: The prompt, The file's contents.

text_fieldstringrequired

The field a plain text filter over this input uses: contains and matches pattern are filters over prompt_text, attachment_text, body, artifact_text or artifact_path, not engine filters.

interaction_kindsInteractionKind[]required

The sub-categories a Network policy may pick: today just Attachment, for prompt; empty for every other subject. A policy picks at most one; none means any interaction.

idstringrequired
labelstringrequired
redact_refusalstring · null

Why a Redact response is refused under this kind, or absent when it is not. No kind carries one today: a text attachment is rewritten, and a binary one carrying a named type is withheld.

predicatesPredicateSpec[]required

Every filter field for this type, each with what it is worth in this workspace. Fields this workspace cannot answer yet are listed too.

categorystringrequired

The group this field is listed under: destination | application | identity | content | finding | context.

covered_machinesintegerrequired

Machines in this workspace on which this predicate can be evaluated.

kindstringrequired

The filter's kind, exactly as a policy body writes it: service_is, body_contains, engine_label, and so on.

labelstringrequired

The field's display name, and only the name.

locusstringrequired

agent | server — where a filter over this field is answered: on the machine, or by Oxelone. One server-side filter moves the whole policy to the server.

operatorsOperator[]required

The comparisons that can be evaluated over this field, in the order to offer them. Any other comparison is refused.

sourcesSourceCoverage[]required
carries_contentbooleanrequired

Whether machines on this tactic capture content. False for metadata and none, where content filters cannot match.

machinesintegerrequired
sourcestringrequired

A capture tactic: extension, redirect, mitm_ca, metadata or none.

One machine is on exactly one tactic, so these counts sum to the workspace's live machine count.

subjectstringrequired

The policy type this document answers for, echoed back from the request.

categoriesServiceCategory[]

The service categories a filter with takes_categories may name, written $slug. Absent on a type with no such filter.

descriptionstringrequired

One line on what it covers.

display_namestringrequired

A name, never a sentence: Criminal AI.

membersServiceCategoryMember[]required
originstringrequired

vendor (Oxelone's: additions only) or workspace (this workspace's own: renamed, described and deleted here).

slugstringrequired

What a policy stores: $criminal-ai.

policiesinteger · null

How many of this workspace's Network policies name it. Only the Coverage Matrix's list carries it.

connectorConnectorCapability · null

Everything the Connector trigger needs, and null on every other trigger.

actionsConnectorActionCapability[]required
connectionsConnectionOption[]required

The live connections this workspace has. Always present on a Connector document, because the trigger step's first control is this Select.

record_kindsRecordKindCapability[]required

Empty without connection=: a record kind is a fact about one connection's credential, and answering for "any of them" would offer a catalogue no connection has.

fix_kindsFixKind[]

The kinds of Fix a policy may apply. Host (file_artifact) only; absent on every other trigger.

applies_tostring[]required
kindstringrequired
labelstringrequired
needsstringrequired

What the row needs from the author: filter (it acts on what the filter matched), list (rules or sources typed in), mode (a start mode picked) or none.

hookHookTrigger · null

The Hook trigger: one action kind per policy. Ask with subject=hook&action=<kind> for the filters that kind offers.

kindsHookKind[]required

The eight kinds, in picker order.

actionstring · null

The action this document's predicates and actions are for — the query's action — or null when none was asked, in which case predicates is every Hook filter and each kind's fields narrows it.

lock_toolsstring[]

The AI tools a Lock is held on, as tool ids in a fixed order. A Lock that matches a tool outside this list does not hold on it. Hook and Host only; absent elsewhere.

Errors

400

The policy type is missing or unknown

401

No valid session

403

Caller lacks policies:read in this workspace

404

No such workspace, or the caller is not a member

Create a group of this workspace's own policies

POST/policy-groups

Request bodyCreateGroupRequest

namestringrequired
subjectstringrequired

prompt, file_artifact or hook.

descriptionstring
policy_idsstring[]

Members, in order: this workspace's own policies of subject, in no other group.

Response201

The group as stored, On

descriptionstringrequired
enabledbooleanrequired

On (true) or Off. Off pauses every member.

idstringrequired
member_idsstring[]required

The members, in member order.

namestringrequired
removedbooleanrequired

A provided group this workspace removed (listed with the removed policies).

subject_kindstringrequired

prompt (Network), file_artifact (Host) or hook (Hook).

provided_bystring · null

oxelone for a provided group; absent for the workspace's own.

vendor_versioninteger · null

A provided group's content version: it moves when Oxelone changes the name, the description or the members. Absent for an own group.

Errors

400

Unknown type, a blank name, or a policy that may not be a member: not this workspace's, provided, of another type, or already in a group

401

No valid session

403

Caller lacks policies:write in this workspace

404

No such workspace, or the caller is not a member

Reorder policy groups

PUT/policy-groups/order

Sets the order one policy type's groups are read in. It changes nothing a machine runs.

Request bodySetGroupOrderRequest

idsstring[]required

Every group of that type this workspace has (removed provided ones excepted), in the order they should appear.

subjectstringrequired

prompt, file_artifact or hook.

Response200

Order stored

reorderedintegerrequired

How many groups moved: the number of ids sent, on success.

Errors

400

Unknown type, an id that is not one of this workspace's groups, a group of another type, a duplicate, or an incomplete list

401

No valid session

403

Caller lacks policies:write in this workspace

404

No such workspace, or the caller is not a member

Update a policy group

PUT/policy-groups/{id}

Rename, describe, or set the members of one of this workspace's own groups.

Path parameters

idstringrequired

Request bodyUpdateGroupRequest

descriptionstring · null
namestring · null
policy_idsstring[] · null

Response200

The group as stored; the bundle republished when an Off group's members changed

groupGrouprequired

One group on a workspace's wire. Provided and own alike; a provided one says provided_by and vendor_version.

descriptionstringrequired
enabledbooleanrequired

On (true) or Off. Off pauses every member.

idstringrequired
member_idsstring[]required

The members, in member order.

namestringrequired
removedbooleanrequired

A provided group this workspace removed (listed with the removed policies).

publishCompileResponse · null
haltedbooleanrequired

Whether this publish happened while enforcement is halted, and therefore enforces nothing whatever the policy list says.

hashstringrequired
warningsCompileWarning[]required

Policies that compiled but cannot fire in this workspace as it is configured — almost always because of which backend an engine is set to. Empty is the normal case.

A warning and not a refusal: such a policy is undetermined rather than invalid, and refusing the compile would let switching a backend brick publishing for a whole workspace. Silence was the other option, and it is the worse one — an operator would leave a policy in enforce believing it covers something nothing is looking for.

Errors

400

A blank name, or a policy that may not be a member

401

No valid session

403

Caller lacks policies:write — or policies:publish, when the change takes an Enabled policy out of an Off group

404

No such group in this workspace

409

The group is provided by Oxelone; its content cannot be edited here

Delete or remove a policy group

DELETE/policy-groups/{id}

Deletes one of this workspace's own groups (its policies stay, in no group), or removes a group provided by Oxelone and its policies from this workspace; a removed provided group can be restored.

Path parameters

idstringrequired

Response200

Deleted, or removed for this workspace; the bundle republished when what runs changed

publishCompileResponse · null
haltedbooleanrequired

Whether this publish happened while enforcement is halted, and therefore enforces nothing whatever the policy list says.

hashstringrequired
warningsCompileWarning[]required

Policies that compiled but cannot fire in this workspace as it is configured — almost always because of which backend an engine is set to. Empty is the normal case.

A warning and not a refusal: such a policy is undetermined rather than invalid, and refusing the compile would let switching a backend brick publishing for a whole workspace. Silence was the other option, and it is the worse one — an operator would leave a policy in enforce believing it covers something nothing is looking for.

Errors

401

No valid session

403

Caller lacks policies:write — or policies:publish, when deleting an Off group resumes an Enabled policy

404

No such group in this workspace, or a provided group it already removed

409

A Connector group: its rules are switched on each connection, not by the group

Restore a provided policy group

POST/policy-groups/{id}/restore

Brings back a group provided by Oxelone that this workspace removed, with its policies, each in the state it had.

Path parameters

idstringrequired

Response200

Restored with its policies; the bundle republished

groupGrouprequired

One group on a workspace's wire. Provided and own alike; a provided one says provided_by and vendor_version.

descriptionstringrequired
enabledbooleanrequired

On (true) or Off. Off pauses every member.

idstringrequired
member_idsstring[]required

The members, in member order.

namestringrequired
removedbooleanrequired

A provided group this workspace removed (listed with the removed policies).

publishCompileResponse · null
haltedbooleanrequired

Whether this publish happened while enforcement is halted, and therefore enforces nothing whatever the policy list says.

hashstringrequired
warningsCompileWarning[]required

Policies that compiled but cannot fire in this workspace as it is configured — almost always because of which backend an engine is set to. Empty is the normal case.

A warning and not a refusal: such a policy is undetermined rather than invalid, and refusing the compile would let switching a backend brick publishing for a whole workspace. Silence was the other option, and it is the worse one — an operator would leave a policy in enforce believing it covers something nothing is looking for.

Errors

401

No valid session

403

Caller lacks policies:write in this workspace, or policies:publish when an Enabled policy of an On group would start enforcing

404

Not a provided group this workspace removed

Turn a policy group On or Off

PUT/policy-groups/{id}/state

Off pauses every member: each reads as Disabled and keeps its own state. On restores each as it was set.

Path parameters

idstringrequired

Request bodySetGroupStateRequest

enabledbooleanrequired

true is On, false is Off.

Response200

Switched, and the bundle republished in the same request

groupGrouprequired

One group on a workspace's wire. Provided and own alike; a provided one says provided_by and vendor_version.

descriptionstringrequired
enabledbooleanrequired

On (true) or Off. Off pauses every member.

idstringrequired
member_idsstring[]required

The members, in member order.

namestringrequired
removedbooleanrequired

A provided group this workspace removed (listed with the removed policies).

publishCompileResponse · null
haltedbooleanrequired

Whether this publish happened while enforcement is halted, and therefore enforces nothing whatever the policy list says.

hashstringrequired
warningsCompileWarning[]required

Policies that compiled but cannot fire in this workspace as it is configured — almost always because of which backend an engine is set to. Empty is the normal case.

A warning and not a refusal: such a policy is undetermined rather than invalid, and refusing the compile would let switching a backend brick publishing for a whole workspace. Silence was the other option, and it is the worse one — an operator would leave a policy in enforce believing it covers something nothing is looking for.

Errors

401

No valid session

403

Caller lacks policies:write — or policies:publish, to switch on a group holding an Enabled policy

404

No such group in this workspace, or a provided group it removed

409

A Connector group: its rules are switched on each connection, not by the group