Promote a recommendation
AIControls recommends grants from a workload's own unmatched and gate-denied calls. When you promote a recommendation, AIControls adds exactly the previewed entry to an Access Binding, and the next identical call matches it. Binding contents are live, so no rollout is needed. The same queue holds intent recommendations, for a workload that does more than its intent declares; see Promote an intent recommendation.
Workload Trust is available only in private, self-managed AIControls installations, on premises or in a cloud cluster that you run. It needs a dedicated cluster that you run, with Kyverno, Kyverno Runtime, and cluster OIDC and RBAC access in place. Nirmata-hosted (SaaS) workspaces don't include it. See Feature availability.
Before you begin
- You need an administrator session. Every endpoint on this page is administrator-only and requires the
clusterquery parameter: the UID of the cluster'skube-systemnamespace. Until the controller can read thekube-systemnamespace, it keys the cluster by its display name instead. AIControls refuses identity binding writes (create, update, and retire), access writes, mode changes, contains, recommendation promotions and dismissals, and grant denies from the AI access tab that name that display name ascluster, with409 cluster_identity_unavailable, because configuration written under the display name wouldn't carry over once the UID resolves. Wait for the UID, then retry with it ascluster. Release stays allowed under the display name, because containment moves to the UID when it resolves. If it has already moved, a release that names the display name returns409 cluster_identity_changedand releases nothing; retry with the UID ascluster. - The workload needs a Workload Registration, so that it has an access policy to promote into. See Workload access.
- A grant promotion works in either mode, with one exception. The first promotion that creates the workload's own binding, or that adds a binding to the workload's override, works only in Audit. For an Enforce workload, AIControls returns
409 audit_required: switch the workload to Audit, promote, and then switch it back to Enforce. After that, a promotion applies from the next call in either mode, so review the preview first. An intent promotion works in either mode. See Promote an intent recommendation. - AIControls rebuilds the recommendation queue from the audit trail every 5 minutes. A call made a moment ago may not appear yet.
The Recommendations card on the AI access tab of the workload detail page shows this queue, and the steps below give the API calls. In the card, open a row's actions menu and select Promote to open the Promote recommendation dialog. Choose the Target binding. The default, Extra access for this workload, is the workload's owned binding. Review Before and After, and select Promote. Select Dismiss in the same menu to close a recommendation. In the dialog for a shared binding, the Subjects who gain it row lists each subject that gains the entry, and Also affects lists the Blueprints and workloads. The table pages and sorts on the server and shows the total. Promote all previews every open entry, on every page. Its confirmation shows a Review before you promote alert when an LLM entry grants the model on every provider, or when the workload's own deny list blocks an entry. After you confirm, it adds every open entry to the extra access for this workload and stops at the first failure. Promote all covers grant recommendations only; it leaves intent recommendations, tagged Intent, in the queue.
Review the recommendations
List the open recommendations for the workload:
GET /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations?cluster={cluster}Each grant recommendation (facet
mcporllm) names one candidate grant inentry: an MCPserverandtool, or an LLMmodel. An intent recommendation (facetintent.network,intent.files,intent.exec, orintent.kubernetes) names asection, thetierthe workload's behavior needs, and itseffectiveTier; see Promote an intent recommendation. Itsevidenceshows how many calls it covers, when they happened, the policy that decided the newest call (decisionSource), and up to three audit event IDs you can open in the audit log. Evidence never contains prompts, request bodies, tool arguments, tool results, or responses.The list is paged on the server. Add
page(from 1) andpageSize(1 to 211, default 50); the response reportstotal,page, andpageSize. Addsortwithcount,firstSeen, orlastSeen, prefixed with-for descending, to order every page on the server; without it the queue keeps its default order (facet, calls, then most recent). Addstatus=dismissed,promoted,expired,resolved, orallto review closed recommendations. One page of 211 always holds the whole open queue, because a workload keeps at most 100 open grant recommendations per facet and at most 11 open intent recommendations.Check
truncated. When it istrue, the workload produced more than 100 distinct candidates on at least one facet, and the queue shows the 100 with the most calls for that facet.overflowis a map keyed by facet (mcporllm); each value hastruncated,droppedCandidateCount(how many distinct candidates were dropped), andoldestIncludedAt(the oldest sighting still in the queue). For example,"overflow": {"mcp": {"truncated": true, "droppedCandidateCount": 37, "oldestIncludedAt": "2026-09-30T12:00:00Z"}}. Promote the most important entries first, or tighten the workload before you promote everything.For an LLM recommendation, check
entry.providerUnresolved. When it istrue, the audit trail didn't record which provider served the call, so promoting it grants the model on every provider.
Preview the promotion
Preview the change. Send an empty body to promote into the workload's owned binding:
POST /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations/{id}/preview?cluster={cluster}{}To promote into a shared binding that the workload already references, name it:
{"bindingId": "ab_github_read"}Read the preview before you continue:
Field What to check before,afterThe binding's tool and model selectors before and after the change. Only the recommended entry is added. createsBindingtrueon the first promotion into the owned binding. AIControls creates it with no subjects; only this workload reaches it.addsReferencetruewhen the promotion also adds the workload's own binding to its override.impactWho gains the entry. For a shared binding, this lists every subject on the binding and every workload and Blueprint that references it. warningsWider-scope effects, such as a shared binding, an exact-model-only grant, or an entry that the workload's own deny list blocks. previewHashThe value you send with Promote.
Promote or dismiss
Promote with the preview hash:
POST /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations/{id}/promote?cluster={cluster}{"previewHash": "…"}Include the same
bindingIdyou previewed when you promote into a shared binding. AIControls checks that nothing changed since the preview. If the recommendation, the binding, or the registration changed, it returns409with the codepreview_staleand writes nothing; preview again.Make the call again. It now matches the binding's grant instead of the default access policy, and the workload's unmatched rate drops as new calls arrive.
To close a recommendation without granting anything, dismiss it:
POST /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations/{id}/dismiss?cluster={cluster}A dismissed recommendation stays closed even when the same call happens again.
Each promotion records one workload_access_recommendation.promoted configuration audit event, and each dismissal records workload_access_recommendation.dismissed. If the audit write fails, AIControls rolls the whole change back.
Promote an intent recommendation
An intent recommendation means the workload's observed behavior needs a wider tier than its effective intent, for example exec: none → shell for a workload that runs a shell. Its evidence names the kind of source and a count, never the observed binary, host, or server. You can promote it to this workload or to the workload's Runtime Binding. Both are administrator-only.
In the Recommendations card, an intent recommendation has an Intent tag, such as Intent · Execution. Its actions menu offers Promote to this workload, Promote to the Runtime Binding, and Dismiss.
Promote to this workload
Preview the override change:
POST /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations/{id}/intent/preview?cluster={cluster}overrideBeforeandoverrideAfterare the workload override's intent,effectiveChangesis how the effective intent changes, andwideningslists every field that the new override makes wider than the Runtime Binding.enforceLiveistruefor a workload in Enforce mode: the promotion changes the workload's enforced access and runtime rules as soon as you confirm, andwarningssays so. In the dialog, an alert reads This workload is in Enforce: its enforced rules change as soon as you promote. The preview hash covers the workload's mode. If the mode changes after you preview, the promotion returns409 preview_stale.Promote with the preview hash. When
requiresAcknowledgementistrue, addacknowledgeWidening. In the Promote to this workload dialog, which shows Override before, Override after, Effective intent, and Wider than the Runtime Binding, select the acknowledgment checkbox that ends with "I reviewed the widening."POST /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations/{id}/intent/promote?cluster={cluster}{"previewHash": "…", "acknowledgeWidening": true}AIControls writes the workload's override, recomputes its effective intent, and closes the recommendation, in one transaction.
Promote to the Runtime Binding
The Runtime Binding holds the access levels that every Blueprint and workload using it runs with. This target drafts the change and doesn't write it, because the change reaches other workloads.
Get the draft:
GET /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations/{id}/intent/blueprint-draft?cluster={cluster}The draft has
levelsBeforeandlevelsAfter, the Runtime Binding's levels with the one section widened. Itsupdatefield is the request body to preview and save, without thepreviewHash.warningssays when the workload's override already sets the section, so the binding change doesn't reach it.alreadyCoveredistruewhen the Runtime Binding already allows the tier.Preview the change with
POST /api/v1/workload-runtime-bindings/{id}/previewand the draft's fields. The preview lists every Blueprint and workload that uses the Runtime Binding and what the change does to it. In the UI, Promote to the Runtime Binding opens a dialog that shows the draft's Levels before and Levels after. Select Preview impact to see the impact, and then select Confirm and save. If the Runtime Binding already allows the tier, the button reads Close the recommendation. See What the impact preview shows.Save it with
PUT /api/v1/workload-runtime-bindings/{id}, the preview hash, andfromRecommendation, which names the recommendation. A Runtime Binding save needs no widening acknowledgment, because the impact preview is the confirmation:{"fromRecommendation": {"tuple": {"cluster": "…", "namespace": "prod", "kind": "Deployment", "name": "checkout"}, "id": "rec_…", "reviewHash": "<copy from draft.update.fromRecommendation>"}}Copy the complete
updatefrom the draft, includingfromRecommendation.reviewHash, then add the impactpreviewHash. The source review hash binds the recommendation evidence and workload state; it is separate from the fleet impact hash. If either review becomes stale, fetch the draft again and review the impact before saving.The save closes the recommendation in the same transaction. It refuses with
409 recommendation_mismatchwhen the recommendation's workload doesn't use this Runtime Binding, and with409 preview_stalewhen the recommendation is no longer open or the saved levels don't allow the tier.
Both targets record a workload_access_recommendation.promoted configuration audit event with the target, the section, and the tier.
Work with the workload's own binding
The workload's own binding is an ordinary Access Binding with an owner field, {"kind": "workloadRegistration", "ref": "<cluster>/<namespace>/<kind>/<name>"}. It appears in Setup → Settings → Access Bindings, and GET /api/v1/access-bindings?owned=true lists only owned bindings.
You can't edit or delete it from the Access Bindings page or API; those requests return 409 with the code owned_binding. Change it by promoting recommendations. To stop granting its entries, remove its ID from the workload's override with PUT /api/v1/workloads/{namespace}/{kind}/{name}/access. The change takes effect from the next call, in either mode.
Troubleshooting
| Response | Cause | Fix |
|---|---|---|
409 invalid_target | The shared binding is missing, disabled, not an allow binding, owned by a workload, or not referenced by this workload. | Select the binding in the workload's Blueprint or reference it in the workload's override first, or promote into the workload's own binding. |
409 preview_stale | Something changed after the preview: the recommendation, or the target binding. | Preview again and promote with the new hash. |
409 owned_binding_reference | A Blueprint or another workload's override references a workload-owned binding. | Reference a shared binding instead. Only the owning workload reaches its owned binding. |
404 not_found | The recommendation is no longer open: it was promoted, dismissed, expired, or resolved. | List the recommendations again. |
409 recommendation_kind | You sent a grant Promote for an intent recommendation, or an intent Promote for a grant recommendation. | Use the intent/... endpoints for a facet that starts with intent.. |
409 widening_unacknowledged | Promote to this workload makes its intent wider than its Runtime Binding. | Review widenings, then promote again with acknowledgeWidening. |
409 audit_required | A grant promotion would create the workload's own binding, or add it to the override, and the workload is in Enforce. | Switch the workload to Audit, promote, and then switch it back. |
409 recommendation_mismatch | A Runtime Binding save named a recommendation for a workload that doesn't use that binding. | Get the draft from the workload's own recommendation, which names the right binding. |