Skip to content

POLICY.md Specification

Version: 0.2.0
Status: Draft
License: Apache-2.0

A POLICY.md file is a portable, Markdown-native negative-capability manifest for AI agents. It declares what an agent must not do, must ask before doing, and is allowed to do.

1. File format

Every POLICY.md file is a Markdown file with YAML frontmatter delimited by ---:

markdown
---
name: project-guardrails
version: 1.0.0
scope: project
appliesTo: [all]
rules:
  - capability: file.write
    action: deny
    condition:
      field: { path: payload.path, op: includes, value: .env }
    reason: Never write .env or secret files
---

## Forbidden
- Never commit `.env` files or any file containing credentials.

The frontmatter contains machine-enforceable rules. The Markdown body contains human-readable policy sections.

2. Frontmatter schema

Top-level fields

FieldRequiredTypeDescription
nameyesstringUnique policy identifier, kebab-case or snake_case.
descriptionnostringHuman-readable summary.
versionnostringSemantic version or opaque policy version.
scopenostringOne of project, skill, agent, department. Default: project.
appliesTonostring[]Agent or skill ids this policy applies to. ["all"] means every agent. Default: ["all"].
severitynostringOne of block, warn, require_approval. Default: block.
rulesnoRule[]Machine-enforceable rules.

Rule schema

FieldRequiredTypeDescription
idnostringStable rule identifier.
capabilityyesstringCapability pattern, e.g. file.write, payment.*, *.
actionyesstringallow, deny, or require_approval.
conditionnoConditionWhen the rule applies. Omit to match every intent.
reasonnostringExplanation returned to the agent/runtime.
prioritynonumberHigher number wins ties. Default: 0.
descriptionnostringHuman-readable rule note.

Capability patterns

  • Exact: file.write matches file.write.
  • Single-segment wildcard: payment.* matches payment.send, payment.refund, etc.
  • Global wildcard: * matches every capability.

Condition schema

A condition is exactly one of:

yaml
condition:
  field: { path: payload.path, op: includes, value: .env }

condition:
  and:
    - field: { path: payload.amount, op: gt, value: 1000 }
    - field: { path: constraints.environment, op: eq, value: production }

condition:
  or:
    - field: { path: workerId, op: eq, value: payment-bot }
    - field: { path: specialist, op: eq, value: payment-bot }

condition:
  not:
    field: { path: constraints.environment, op: eq, value: development }

Field condition

FieldRequiredTypeDescription
pathyesstringDotted path into the ActionIntent object.
opyesstringOperator name.
valuedependsanyRight-hand value.
valuesdependsany[]Right-hand array for in/notIn.

Operators

OperatorNeeds valueNeeds valuesDescription
eqyesnoStrict equality.
neqyesnoStrict inequality.
gtyes (number)noGreater than.
gteyes (number)noGreater than or equal.
ltyes (number)noLess than.
lteyes (number)noLess than or equal.
includesyesnoArray includes value, or string contains substring.
innoyesField value is in array.
notInnoyesField value is not in array.
existsnonoField is defined and not null.
notExistsnonoField is undefined or null.
wildcardnonoAlways true.

Resolvable paths

  • payload.<key> - arbitrary payload field supplied by the tool.
  • constraints.<key> - action constraints (environment, resourceId, maxAmount, ...).
  • requester.<key> - requester metadata (type, id, tenantId).
  • risk, actionType, actionClass, reversibility, capability, specialist, workerId, toolName, connectorId.

3. Markdown body

The Markdown body is optional but strongly recommended. It is inserted into the agent system prompt by buildPoliciesContext(). Conventional sections:

  • ## Forbidden - absolute negative boundaries.
  • ## Ask first - actions that require human approval.
  • ## Allowed - safe actions the agent may take freely.

Runtimes may render the body as-is or summarize it.

4. File discovery

A PolicyManager searches the following locations:

  1. <workingDir>/POLICY.md (project root).
  2. <workingDir>/<policyDir>/POLICY.md for each configured policy directory.
  3. <workingDir>/<policyDir>/<name>/POLICY.md for each subdirectory.
  4. <workingDir>/<skillDir>/<name>/POLICY.md when a SKILL.md or skill.md exists in the same directory.

Default policy directories: .policies, .devin/policies, .sidian/policies.
Default skill directories: .devin/skills, .sidian/skills, .opencode/skills, .claude/skills.

Skill-attached policies inherit scope: skill and appliesTo: [<skillName>]. Their rules are automatically scoped to the matching workerId or specialist at runtime.

5. Runtime semantics

ActionIntent

When a tool is about to run, the runtime builds an ActionIntent:

ts
interface ActionIntent {
  id: string;
  workRunId: string;
  taskId?: string;
  workerSessionId?: string;
  workerId: string;
  specialist: string;
  actionType: 'tool' | 'connector' | 'command' | ...;
  capability: string;
  toolName?: string;
  connectorId?: string;
  actionClass?: 'read' | 'write' | 'execute' | 'connect';
  reversibility?: 'reversible' | 'conditional' | 'irreversible';
  riskLevel: 'low' | 'medium' | 'high' | 'critical';
  payload: Record<string, unknown>;
  constraints?: ActionConstraints;
  requester: ActionRequester;
  createdAt: number;
}

AuthorizationEngine

  1. Collect all rules whose capability pattern matches the intent's capability.
  2. Evaluate each rule's condition against the intent.
  3. Among matching rules, select the highest priority.
  4. If multiple rules share the top priority, the first one wins.
  5. Return allow, deny, or require_approval plus the matched rule id and reason.
  6. If no rule matches, the default is allow.

Composite engines

Multiple engines can be composed. The most severe decision wins:

deny > require_approval > allow

6. Agent context

buildPoliciesContext(manager) renders every loaded policy as Markdown suitable for injection into an agent system prompt. buildAgentPoliciesContext(manager, agentId) filters to policies whose appliesTo includes all or the given agent id.

7. Validation

PolicyValidator checks:

  • Required frontmatter fields and valid types.
  • Valid scope, action, and op values.
  • Required value/values for each operator.
  • YAML syntax with line numbers.
  • Unknown fields when strict: true.

8. Distribution

Policies can be published as repositories and installed with the CLI:

bash
policy install owner/repo

Installed policies live in .policies/<name>/POLICY.md.

9. Framework adapters

The @sidianlabs/policy/adapters/codex module converts policies into OpenAI Codex-compatible formats:

  • toCodexExecpolicy(files) → Starlark execpolicy rules.
  • toCodexGuardianPrompt(files) → Guardian LLM-judge prompt text.

10. Versioning

This specification follows semantic versioning. A policy version is advisory; runtimes should treat the latest loaded copy of a policy as authoritative unless they implement version pinning.

Released under the Apache 2.0 License.