Skip to main content
A policy is the mechanism by which a board author’s intent reaches an agent at the exact moment it matters. There are two types: transition_guard blocks a move until conditions are met, and agent_responsibility fires a message into the write envelope without blocking. Both share the same outer shape; everything that differs lives in definition.

The Policy Envelope

type is immutable after creation — update_policy will not change it. Decide the type before you create the policy.

transition_guard — Blocks a Move

string
required
A group id, or "*" to match any source group.
string
required
A group id, or "*" to match any destination group. Use "*"done for a definition-of-done gate.
Condition[]
An implicit all_of. Each condition is evaluated against the task as it would look after the move — so you can require fields that are set in the same update that moves the task.
string | null
What the agent is told when the move is blocked. Write it as an instruction, not a description — it is the agent’s next action.
The guard engages when the move matches; when engaged, the move fails with transition_blocked unless every require condition passes. Use "*"done for a definition-of-done gate that catches every path into the final column.

agent_responsibility — Advises, Never Blocks

Condition[]
Conditions that trigger the message. Absent or empty matches always — the message fires on every write to this board.
string
required
Surfaced in the write’s policies_fired envelope. Write it as a direct instruction to the agent reading the response.

Conditions

A leaf condition is { field, op, value?, values? }. Field references resolve literal-first, then custom_data — so a custom field is task.<name>, and built-ins like task.group_id, task.title, task.description, and task.parent_id work too.

Operator Reference

Compound Conditions

Nest compounds freely:
Operators never throw. A type mismatch, bad operand, or unparseable regex evaluates to false — a malformed policy can never crash a write. The trade-off is that a wrong field path reads as “condition not met” rather than as an error, which is why you validate. String operators coerce scalars but not arrays: a string_list field will not match contains. Use has_any / has_all instead. matches_regex compiles author-supplied patterns — patterns over 1000 chars, non-strings, and anything that throws are treated as non-match.

Validation at Author Time

Definitions are validated strictly against their type at create_policy / update_policy time and on load. A misspelled key or unknown operator produces a schema_violation error — it is not silently ignored. This catches shape errors, but not a wrong from_group, a wrong to_group, or a field path that resolves to nothing. For those, see Validate Gates.

Priority and enabled

priority orders evaluation among policies on the same board — lower numbers run first. Use it when the order of policies_fired messages matters. enabled: false keeps a policy in the file as documentation without enforcing it — useful for gates you’re still drafting or have temporarily suspended.