Visual builder
A graph-based editor for Cedar policies. Round-tripped to ensure visual + actual Cedar never drift.
The visual builder is a graph view of your Cedar policy. Drag actions, scope by resource, gate by condition — the editor emits Cedar in real time. Every save round-trips through the parser: visual → IR → Cedar → parsed IR. If the round-trip doesn't match, the save fails. You cannot ship a policy where the visual and the actual Cedar disagree.
Open the builder
On any policy detail page → Visual tab.

The five primitives
- 1Permit / Forbid blocks
Start with + Permit. Cedar's default is deny; permits are what allow. Forbid blocks override permits.
- 2Action sets
Drag actions into the permit's action input. Auto-grouped by provider. Pick individual actions or whole groups (e.g. all GitHub read actions).
- 3Resource conditions
resource.owner == "acme"— type in the visual builder's condition input. The builder hints valid keys from the YAML adapter (owner, repo, channel, account_id…). - 4Context conditions
context.cosigner == true— the gate for step-up. Orcontext.now.hour >= 9for business hours. Context keys come from the PDP — see Dynamic intent. - 5Principal scoping
Rarely needed — most policies apply to "this App" by default. If you're writing a cross-app policy, scope to specific principals here.
A worked example
Goal: allow read on every GitHub action, allow PR create only on acme/app, forbid
deletes unless cosigner is true.
- + Permit → drag GitHub read actions → no conditions → save.
- + Permit → action
/github/pr/create→ resourceowner == "acme" && repo == "app". - + Forbid → actions matching
*/delete*→ condition!context.cosigner.
The emitted Cedar (right pane):
permit ( principal, action in [Action::"/github/issue/list", Action::"/github/issue/get",
/* … */], resource );
permit ( principal, action == Action::"/github/pr/create", resource )
when { resource.owner == "acme" && resource.repo == "app" };
forbid ( principal, action like "/github/*/delete", resource )
when { !context.cosigner };
What the round-trip guarantees
Visual = Cedar.
When you click save, the builder serializes the canvas to IR, emits Cedar, parses it back, and compares. Mismatch = block save with a diff message. You cannot ship a policy whose visual and Cedar disagree.
This matters because:
- A buggy visual editor could otherwise show "deny on delete" while emitting Cedar that allows delete. That class of bug becomes unshippable.
- New visual features (e.g. a new condition operator) ship only when the round-trip succeeds for every existing policy.
When to drop to Cedar
- Multi-clause
unlessconditions. - Custom UCAN attribute lookups (
principal.delegationDepth < 3). - Cross-resource invariants.
Switch tabs to Source. Edit Cedar directly. The visual tab re-parses on the next load.