Typed Policy on a New Installation
A fresh installation is governed from its first request, with nothing to author. Until an organization activates a document of its own, it runs the shipped policies together with the deployment's baseline permissions; Shipped Policy Posture lists every shipped policy and its action. This page is the path to follow when you want policy of your own: the vocabulary a policy is written against, what runs before you publish, and how to publish, activate and roll back a document.
If you are upgrading from v10.x, read the v10 → v11 Migration Guide first: the legacy policy tables are read-only, and policies you authored there are not carried forward.
The typed model is AxonFlow's deterministic decision point: policies are authored as a signed, versioned document validated against a vocabulary of registered actions, trust realms and resource types, compiled to a bundle, and activated by content digest. It replaces string-matched rules with a model that can say why a decision was made and reproduce it later.
1. The deployment vocabulary
A vocabulary decides which actions, trust realms and resource types a policy may name. A deployment's own vocabulary is the default, so no variable is needed to author policies; AXONFLOW_TYPED_AUTHORING_CATALOG is honoured if it is set.
| value | what it loads | can it be activated? |
|---|---|---|
deployment (the default) | This deployment's own vocabulary: its registered actions, the trust realms its identity plane mints principals in, its build's enforcement planes, and the shipped inspection controls | Yes - this is what a real installation runs |
conformance | The conformance fixture world, used by AxonFlow's own test corpus | No - publishable and validatable, never activatable |
Setting conformance on a deployment that intends to enforce will let you publish and then refuse the activation, naming the variable and the value to set. Enforcing a vocabulary no real request can arrive in is not a supported posture. Use deployment.
With any other value the Orchestrator's typed-policy routes answer 503 naming the variable, and the customer portal does not register its typed-policy routes: a value nobody chose must not select a policy vocabulary.
What the deployment vocabulary contains
Nothing in it is hand-maintained - it is derived from what your deployment actually has:
- Actions - the governed operations every decision surface already recognises:
llm.completion,tool.callandagent.invoke, each carrying astage:tag so a policy can select a whole stage. - Arguments - every caller-supplied field the shipped controls inspect, at the type they inspect it as, plus
query, which every stage requires. - Trust realms - derived from your identity plane. A realm's two authoring-relevant properties come from its own declaration: whether a person there can answer an approval, and whether it has a group graph. A deployment with no SCIM-backed directory has no realm with a group graph, and a group-scoped policy there is refused as unresolvable rather than silently matching nothing.
- Enforcement planes - the in-process planes your build carries, and the obligations each can discharge.
- Inspection controls - the shipped detector set, anchored to the corpus your binary was built with.
You can read back exactly what your deployment resolved. Calls to the Agent authenticate with your client credentials, and the Agent takes your organization from them, overwriting any X-Org-ID you send.
curl -s -u "$CLIENT_ID:$CLIENT_SECRET" "$AGENT_URL/api/v1/typed-policies/edition" | jq
{
"success": true,
"catalog": "deployment",
"catalog_digest": "sha256:…",
"registry_version": 1,
"catalog_fixture": false,
"constructs": { "…": "what this edition may write" },
"max_documents": 20
}
catalog_digest is the identity of the vocabulary. Two deployments reporting the same digest will accept and refuse exactly the same policies.
2. What runs before you publish anything
The decision model denies what no permission grants, so every organization runs with the deployment's baseline permission pack: one permission per registered action, not a single blanket grant.
{
"id": "baseline.permit.llm.completion",
"authority": "permission",
"root": "organization",
"scope": { "organization": true },
"actions": { "actions": [{ "kind": "action", "type": "Action", "local": "llm.completion" }] },
"where": { "kind": "true" }
}
The pack belongs to the deployment and composes beside your organization's policies whether or not you have published a document. You never publish it yourself, and a document of your own narrows it with constraints rather than re-declaring it. Until you activate a document of your own, your organization runs the shipped policies, the platform's and the organization-editable ones, together with the pack, as one implicit bundle composed and signed in the process: nothing is written to your database.
A permission that selects every action for the whole organization with no condition is rejected at publication (BLANKET_PERMISSION) and again at activation. It would also permit every action registered after it - silently - which is the opposite of a registry. Grant per action, as the baseline pack does: it stops covering an action the day that action leaves your vocabulary.
3. Publish a document of your own
A new document starts from the 22 organization-editable shipped policies. Activating it replaces them with your document's content, so carry the ones you want to keep: the publish response lists any your document drops. Carried from the template, the 22 validate and activate on every edition, because they are the deployment's policies rather than ones your organization wrote. A policy of your own that reads a detector signal (a signal.* attribute) needs Evaluation or Enterprise.
Community and Evaluation publish and activate through this API. On Enterprise a publication must name an approver, and this API names none, so a publication through it is refused with APPROVER_IS_AUTHOR. On Enterprise, publish and activate in the customer portal's policy editor (see Typed Policy Authoring), which also serves comparing versions, rollback and the activation history.
curl -sS -X POST "$AGENT_URL/api/v1/typed-policies/publish" \
-u "$CLIENT_ID:$CLIENT_SECRET" -H 'Content-Type: application/json' \
--data @policy.json | jq '{digest, findings}'
The response carries the digest - the content identity of what you published. Activation names a digest and never a version number, so "which policy produced this decision" survives the next edit.
Separation of duties
On Enterprise, a version is activated by one of its recorded approvers, never by its author, unless the organization has enabled self-approval: an organization with fewer than two eligible approvers may enable it, and each self-approved publication records the reason on its audit row. On Community the rule is off (a single administrator must be able to run their own deployment), but the activation is still attributed - an unattributed change of enforced policy is refused on every edition.
4. Activate
curl -sS -X POST "$AGENT_URL/api/v1/typed-policies/activate" \
-u "$CLIENT_ID:$CLIENT_SECRET" -H 'Content-Type: application/json' \
--data '{"digest":"sha256:…","reason":"first organization document"}' | jq
Activating your document replaces the implicit bundle for your organization, by digest. The platform policies and the deployment's baseline permissions keep composing beside it.
Activation is not a pointer flip. Before the digest becomes active, the deployment builds the engine that would enforce it and refuses if it cannot be built. That check is what stops a document becoming active and then failing at the first real request.
An activation is refused, by name, when:
| refusal | meaning |
|---|---|
CATALOG_IS_FIXTURE | the deployment's vocabulary is the conformance fixture (see step 1) |
BLANKET_PERMISSION_REFUSED | the document carries an unbounded grant |
| separation-of-duties conflict | the actor authored the version they are activating (Enterprise) |
| digest not admitted | the digest was never published here |
Read back what is active:
curl -s -u "$CLIENT_ID:$CLIENT_SECRET" "$AGENT_URL/api/v1/typed-policies/active"
What comes back is the byte-exact source that was signed - the document you wrote, not a re-rendering of it.
5. What the platform enforces alongside your policies
Your organization's document is not the only thing in force. AxonFlow ships the platform policies as a system-root document that no organization document can edit: an organization policy grants only within the platform's constraints. Each platform policy can still be disabled, re-enabled or re-actioned for your organization, through per-policy control rather than through your document.
A plane enforces the policies it can actually evaluate. The shipped set is the union of policies across every enforcement plane, and each plane runs the subset whose inputs it produces. A plane with no media pipeline does not run the media policies; a plane that never sees a response does not run response-phase policies. This is derived from the platform's own declarations, not configured, and it is why the number of policies in force differs by plane.
This is deliberate and it is the safe direction: a plane that cannot evaluate a policy does not pretend the policy did not fire.
6. Rolling back
On Enterprise, the customer portal serves rollback and the activation history, under the portal session; rolling back needs the policy:write permission. Rollback re-activates a previously activated digest:
curl -sS -X POST "$PORTAL_URL/api/v1/typed-policies/rollback" \
-b "axonflow_session=$SESSION" -H 'Content-Type: application/json' \
--data '{"digest":"sha256:…earlier…","reason":"over-narrowed the refund grant"}'
Rollback re-verifies the target and is audited exactly as an activation is. It does not re-run approval - the target already passed the gauntlet, was signed, and went through separation of duties once - and it deliberately does not require the version to advance, because restoring an earlier version is the whole operation. What it does not relax is who may perform it: the author of the target version may not roll back to it, unless the organization has enabled self-approval.
Every activation and rollback appends to a history you can read:
curl -s -b "axonflow_session=$SESSION" "$PORTAL_URL/api/v1/typed-policies/artifacts" | jq '.activations'
Each entry names the digest, the digest it replaced, the actor and the reason - which is what makes the history a chain rather than a list. On Community, which has no customer portal, publish and activate a corrected version instead.
7. Checklist for a new installation
-
GET /api/v1/typed-policies/editionreturnscatalog_fixture: falseand acatalog_digest - the people who own your governance posture have read Shipped Policy Posture and decided which shipped policies to disable or re-action for your organization
- if you publish a document, it carries the organization-editable policies you want to keep (carried from the template, they are accepted on every edition), and on Enterprise someone other than its author activates it, unless your organization has enabled self-approval
-
GET /api/v1/typed-policies/activereturns the document you published - on Enterprise, a rollback has been rehearsed once, before you need it
Related
- Policy and Identity Control Plane - what decides a request, and what your organization controls
- Shipped Policy Posture - every shipped policy and its action
- Typed Policy Authoring - the portal's policy editor
- v10 → v11 Migration Guide - upgrading an existing installation
