Skip to content

Structured policy schema

A structured policy is the unit of authorization in Wicket. You edit policies in the dashboard’s policy builder; Wicket compiles them to Cedar for evaluation. This page documents the policy fields. The resource-condition catalog below covers every service that has conditions, listing each condition type by name; the per-service value rules are summarized rather than exhaustively enumerated. For the reasoning behind the structured approach, see Why structured policies.

Core fields

FieldTypeRequiredDescription
namestringyesDisplay name, shown in the policy list and audit entries
servicestringyesConnector this policy applies to: github, slack, linear, … (one service per policy)
effectpermit | forbidyesWhether matching calls are allowed or blocked
toolsstring[]yesTool names the policy covers, e.g. delete_file, merge_pull_request (unprefixed)
principalobjectyesWho the policy applies to — see Principal scope
enabledbooleanyesDisabled policies are ignored at evaluation time
denyMessagestringnoHuman-readable reason shown with denials. Max 500 characters. Only meaningful on forbid policies

Evaluation defaults: a call is denied unless a permit policy matches, and a matching forbid always wins over a matching permit.

Principal scope

{ "type": "all_members" }
{ "type": "specific_members", "userIds": ["<user-id>", "..."] }
ValueEffect
all_membersApplies to every member of the agent
specific_membersApplies only to the listed members — pick them in the builder

Time constraints

All sub-fields optional; omitted fields mean “no restriction on that axis”.

FieldTypeDescription
daysOfWeeknumber[]Allowed days, 0 = Sunday … 6 = Saturday. Empty/absent = all days
hoursFromnumberStart hour, 023 inclusive. Absent = 0
hoursTonumberEnd hour, 023 inclusive. Absent = 23
activeFromISO datePolicy activation date
activeToISO datePolicy expiration date (inclusive)

Repository, channel, and page restrictions

Scope a policy to specific resources, picked from your harvested entities:

FieldServiceShapeMeaning
repoRestrictionsGitHub{ owner, repo? }[]Restrict to repos. Omit repo to match any repo under the owner/org. Empty/absent = no restriction. Max 20 entries
channelRestrictionsSlack{ channelId }[]Restrict to specific channels, chosen from the channel picker. Max 20 entries
notionPageRestrictionsNotion{ pageId }[]Restrict to specific Notion pages. Empty/absent = no restriction. Max 20 entries. Cannot be combined with a database or block notionResourceScope

Resource conditions

Resource conditions match attributes of the resource a tool call targets. Multiple conditions of the same type OR together where noted; different types combine according to resourceConditionMatch.

FieldValuesMeaning
resourceConditionMatchall (default) | anyOuter match across resource-condition groups: all = every group must hold (AND), any = at least one (OR). Applies to resource conditions only — principal, time, session, and repo/channel/page restrictions always AND. Auto-locks to any when two or more concrete resource kinds are active (a resource is exactly one kind, so AND across kinds is unsatisfiable)
githubResourceScopeany | repository | pull_request | issue | branch | releaseGitHub only: restrict the policy to one resource kind. Absent/any = no kind guard
notionResourceScopepage | database | blockNotion only: restrict the policy to one resource kind. Absent = no kind guard. Each scope only permits its applicable condition types (e.g. block scope excludes notionDatabaseId and notionIsPublic)
resourceKindsstring[]Concrete resource kinds explicitly activated in the builder (a tab toggled on, even with no conditions). Drives multi-kind coexistence. Absent = derived from githubResourceScope/notionResourceScope
resourceConditionInnerMatchRecord<kind, "all" | "any">Inner match within each per-kind condition group. Key is the resource kind (common for the kind-agnostic group). Missing key = all. The outer resourceConditionMatch then combines these groups

Condition types by service

The catalog below lists, by service, the resource-condition type names available. Boolean conditions match true/false; string conditions match the exact harvested value; enum conditions are listed with their allowed values.

GitHub — repository attributes

TypeValueMatches
visibilitypublic | private | internalRepository visibility
archivedbooleanArchived state
topicstringRepository topic

GitHub — pull request / issue attributes

TypeValueMatches
stateopen | closed | mergedPR/issue state
hasLabelstringLabel name present
isDraftbooleanDraft PR
isLockedbooleanLocked conversation

GitHub — branch / release attributes

TypeValueMatches
isProtectedbooleanProtected branch
isDefaultBranchbooleanDefault branch
isPrereleasebooleanPre-release

GitHub — entity pickers (values OR together within a type)

TypeValue format
pullRequestowner/repo#N
issueRefowner/repo#N
branchRefowner/repo@ref
releaseRefowner/repo@ref

Slack — channel attributes

TypeValue
isPrivateboolean
isArchivedboolean
isSharedboolean

Linear — issue attributes and pickers

TypeValue
issueStateTypebacklog | unstarted | started | completed | canceled
issuePriorityinteger 04 (0 = no priority, 1 = urgent … 4 = low)
issueHasLabellabel name (manual match)
issueHasLabelIdharvested label ID (stable match)
issueTeamIdteam ID (picker; values OR together)
issueProjectIdproject ID (picker; values OR together)
issueIdissue ID (picker; values OR together)

Vercel — project / deployment attributes

TypeValue
vercelTargetproduction | preview | staging
deploymentStatestring
vercelVisibilitypublic | private

HubSpot — CRM object attributes

TypeValue
lifecycleStagestring
objectArchivedboolean

Stripe — account / customer attributes

TypeValue
customerDelinquentboolean
livemodeboolean

Notion — page / database / block attributes

TypeValue
notionArchivedboolean
notionInTrashboolean
notionDatabaseIddatabase ID (entity equality)
notionParentIdparent entity ID
notionParentTypepage | database | block | workspace
notionIsPublicboolean

Sentry — issue / project attributes

TypeValue
issueLevelstring
issueStatusresolved | unresolved | ignored
isPublicProjectboolean

Hugging Face — repository attributes

TypeValue
repoTypemodel | dataset | space
repoPrivateboolean
repoGatedboolean

Supabase — project / function / bucket / branch attributes

TypeValue
projectStatusstring
regionstring
projectCloudProviderstring
projectInfraComputeSizestring
projectIsBranchEnabledboolean
projectHighAvailabilityboolean
projectIsHibernatingboolean
functionStatusstring
functionVerifyJwtboolean
bucketPublicboolean
branchIsDefaultboolean
branchPersistentboolean
branchStatusstring

PlanetScale — database attributes

TypeValue
dbStatestring

Google / Gmail — message attributes

TypeValue
gmailHasLabellabel name
gmailIsUnreadboolean
gmailFromDomainstring
gmailFromAddressstring
gmailToDomainstring
gmailReceivedSincenumber (timestamp)

Atlassian — Jira issue attributes

TypeValue
atlassianIssueStatusCategorytodo | inprogress | done
atlassianIssueTypestring
atlassianIssuePrioritystring

Airtable — entity selections

TypeValue
airtableBasebase ID
airtableTabletable ID

Network conditions

Network conditions match the source IP of the caller that issued the tool call. They are held in networkConditions, an array of IP conditions. Each entry has the shape:

{ "mode": "exact", "values": ["203.0.113.7"], "negate": false }
{ "mode": "range", "values": ["10.0.0.0/8", "192.168.0.0/16"], "negate": false }
FieldValuesMeaning
modeexact | rangeexact matches a bare IP address; range matches a CIDR block via Cedar’s isInRange
valuesstring[]One or more IPs (exact) or CIDR ranges (range). Multiple values within one condition OR together
negateboolean (optional)When true, the condition is inverted — the call matches when the source IP is not in the set

Rules and limits:

  • exact mode requires bare IP addresses (no /); range mode requires CIDR notation (must include /).
  • At most 20 network conditions per policy, and at most 20 values per condition.
  • Multiple conditions combine with the rest of the policy as an AND (alongside principal, time, and resource scope).

Session conditions

Session conditions make a policy depend on what already happened in the same tool session (one MCP client conversation). See Tool sessions for the session model.

Tool condition — matches when a prior tool was used in this session:

{ "kind": "tool", "service": "github", "tool": "get_file_contents", "minCount": 3 }
FieldDescription
serviceService of the prior tool
toolTool name
minCountMinimum times it was called (default 1)

Policy condition — matches based on how often another policy already fired in this session:

{ "kind": "policy", "policyKey": "<policy-key>", "decisionBucket": "deny", "operator": "gte", "minCount": 3 }
FieldDescription
policyKeyThe other policy’s key
decisionBucketallow or deny — which decisions to count
operatorlt, lte, gt, gte, eq (default gte)
minCountCount threshold

Example use: forbid all tools for the rest of a session after a policy has been denied 3 times — an automatic circuit breaker for misbehaving agents.

Read-only fields

FieldDescription
policyKeyStable identifier used in Cedar output, audit entries, and session policy conditions
triggerCountHow many times this policy matched a call
lastTriggeredTimestamp of the most recent match
cedarPolicyThe compiled Cedar text (visible via Preview)
createdAt / updatedAtTimestamps

Policy versions

Every save creates a version with:

  • A snapshot of the full structured policy
  • The compiled Cedar text
  • Author and timestamp
  • Change type: create, update, toggle, or delete

The dashboard’s Versions view shows a structured field-by-field diff between any two versions (tools added/removed, time window changes, condition changes, deny message changes). Audit entries record the exact policy version that matched a call, so you can always answer “what did the policy say at the time?”

Complete examples

The authoring shape — what you submit on create/update. Wicket adds the server-managed fields (id, policyKey, triggerCount, cedarPolicy, timestamps).

Forbid destructive GitHub tools, with a deny message:

{
"name": "Block GitHub destructive tools",
"service": "github",
"effect": "forbid",
"tools": ["delete_file", "merge_pull_request", "create_repository", "fork_repository"],
"principal": { "type": "all_members" },
"enabled": true,
"denyMessage": "Destructive GitHub operations are blocked. Ask in #platform if you need this."
}

Permit writes during business hours only (Mon–Fri, 09:00–17:00):

{
"name": "Business-hours GitHub writes",
"service": "github",
"effect": "permit",
"tools": ["create_pull_request", "create_or_update_file", "push_files", "add_issue_comment"],
"principal": { "type": "all_members" },
"enabled": true,
"timeConstraints": {
"daysOfWeek": [1, 2, 3, 4, 5],
"hoursFrom": 9,
"hoursTo": 17
}
}

Read-only access scoped to one org’s public, non-archived repos:

{
"name": "Public repos in my-org, read only",
"service": "github",
"effect": "permit",
"tools": ["get_file_contents", "search_code", "list_issues", "list_commits"],
"principal": { "type": "specific_members", "userIds": ["u_7f3k…"] },
"enabled": true,
"repoRestrictions": [{ "owner": "my-org" }],
"resourceConditions": [
{ "type": "visibility", "value": "public" },
{ "type": "archived", "value": false }
],
"resourceConditionMatch": "all"
}

Session circuit breaker — lock the session after 3 denials of the guard policy:

{
"name": "Circuit breaker",
"service": "github",
"effect": "forbid",
"tools": ["*all tools selected in the builder*"],
"principal": { "type": "all_members" },
"enabled": true,
"sessionConditions": [
{
"kind": "policy",
"policyKey": "block-github-destructive-tools",
"decisionBucket": "deny",
"operator": "gte",
"minCount": 3
}
],
"denyMessage": "Session locked after repeated denied attempts. Ask an owner to reset your session."
}