Skip to main content

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.

Self-managed installations only

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 cluster query parameter: the UID of the cluster's kube-system namespace. Until the controller can read the kube-system namespace, 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 as cluster, with 409 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 as cluster. 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 returns 409 cluster_identity_changed and releases nothing; retry with the UID as cluster.
  • 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​

  1. List the open recommendations for the workload:

    GET /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations?cluster={cluster}

    Each grant recommendation (facet mcp or llm) names one candidate grant in entry: an MCP server and tool, or an LLM model. An intent recommendation (facet intent.network, intent.files, intent.exec, or intent.kubernetes) names a section, the tier the workload's behavior needs, and its effectiveTier; see Promote an intent recommendation. Its evidence shows 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) and pageSize (1 to 211, default 50); the response reports total, page, and pageSize. Add sort with count, firstSeen, or lastSeen, prefixed with - for descending, to order every page on the server; without it the queue keeps its default order (facet, calls, then most recent). Add status=dismissed, promoted, expired, resolved, or all to 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.

  2. Check truncated. When it is true, 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. overflow is a map keyed by facet (mcp or llm); each value has truncated, droppedCandidateCount (how many distinct candidates were dropped), and oldestIncludedAt (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.

  3. For an LLM recommendation, check entry.providerUnresolved. When it is true, the audit trail didn't record which provider served the call, so promoting it grants the model on every provider.

Preview the promotion​

  1. 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"}
  2. Read the preview before you continue:

    FieldWhat to check
    before, afterThe binding's tool and model selectors before and after the change. Only the recommended entry is added.
    createsBindingtrue on the first promotion into the owned binding. AIControls creates it with no subjects; only this workload reaches it.
    addsReferencetrue when 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​

  1. Promote with the preview hash:

    POST /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations/{id}/promote?cluster={cluster}
    {"previewHash": "…"}

    Include the same bindingId you 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 returns 409 with the code preview_stale and writes nothing; preview again.

  2. 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.

  3. 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​

  1. Preview the override change:

    POST /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations/{id}/intent/preview?cluster={cluster}

    overrideBefore and overrideAfter are the workload override's intent, effectiveChanges is how the effective intent changes, and widenings lists every field that the new override makes wider than the Runtime Binding. enforceLive is true for a workload in Enforce mode: the promotion changes the workload's enforced access and runtime rules as soon as you confirm, and warnings says 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 returns 409 preview_stale.

  2. Promote with the preview hash. When requiresAcknowledgement is true, add acknowledgeWidening. 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.

  1. Get the draft:

    GET /api/v1/workloads/{namespace}/{kind}/{name}/access/recommendations/{id}/intent/blueprint-draft?cluster={cluster}

    The draft has levelsBefore and levelsAfter, the Runtime Binding's levels with the one section widened. Its update field is the request body to preview and save, without the previewHash. warnings says when the workload's override already sets the section, so the binding change doesn't reach it. alreadyCovered is true when the Runtime Binding already allows the tier.

  2. Preview the change with POST /api/v1/workload-runtime-bindings/{id}/preview and 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.

  3. Save it with PUT /api/v1/workload-runtime-bindings/{id}, the preview hash, and fromRecommendation, 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 update from the draft, including fromRecommendation.reviewHash, then add the impact previewHash. 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_mismatch when the recommendation's workload doesn't use this Runtime Binding, and with 409 preview_stale when 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​

ResponseCauseFix
409 invalid_targetThe 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_staleSomething changed after the preview: the recommendation, or the target binding.Preview again and promote with the new hash.
409 owned_binding_referenceA 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_foundThe recommendation is no longer open: it was promoted, dismissed, expired, or resolved.List the recommendations again.
409 recommendation_kindYou 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_unacknowledgedPromote to this workload makes its intent wider than its Runtime Binding.Review widenings, then promote again with acknowledgeWidening.
409 audit_requiredA 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_mismatchA 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.