Sidian Labs

POLICY.md / Portable Agent Guardrails

You write the boundaries. Agents read them.

A portable, Markdown-native negative-capability manifest for AI agents.

Working Specification

$ git clone https://github.com/SidianLabs/POLICY.md.git

Not on npm yet. Run the CLI from a clone.

Fig. 1Illustrative

A manifest of rules in rows. Denied lines are struck out as solid bars; a reader passes down the file, the way an agent parses POLICY.md before it acts.

01 / What it is

A boundary you must respect.

POLICY.md is a portable way to tell an AI agent what it must not do, what it must ask before doing, and what is allowed. It is the negative-capability counterpart to SKILL.md.

Robots don't read README.md. They need deterministic rules of engagement, context boundaries, and executable constraints. POLICY.md is a working specification for declaring repository policies and constraints to autonomous agents.

  1. 1.1SKILL.md = "here is an ability you can use"
  2. 1.2POLICY.md = "here is a boundary you must respect"

As agents gain tools that can write files, install packages, and call APIs, SKILL.md teaches abilities while POLICY.md enforces boundaries. It combines a human-readable Markdown body with machine-enforceable YAML frontmatter, supporting operators like 'eq', 'gt', and 'includes' across project, skill, or agent scopes.

The same file can be read by a human, understood by an LLM as system context, and enforced by a runtime engine.

Policy files are modular markdown documents that define operational constraints. They are stored in a .policy/ directory at the root of a project, or defined globally in your system directory (e.g., ~/.policy/) for cross-project rules. Agents parse these files before they are permitted to execute tools or propose changes.

Title
Machine-Readable Context
Status
Working Specification
Format
Markdown (.md)
Version
v0.2.0
.policy/infrastructure.mdExample
---
version: 1.0
enforcement: strict
---

# Boundaries
- Agents MAY read any file in `src/`
- Agents MUST NOT modify files in `src/core/auth/` without human review
- Agents MUST NOT run `npm publish`

# Context
The system is built on Next.js App Router. Do not use the Pages router.
Always use Tailwind CSS for styling. Do not write custom CSS.

# Verification
Before proposing a PR, agents MUST run:
`npm run lint` and `npm test`

A policy file in .policy/: frontmatter for the runtime, Markdown for people and models.

Capabilities

  1. 1.3Machine-enforceable YAML frontmatter + Markdown body
  2. 1.4allow / deny / require_approval actions
  3. 1.5Condition operators (eq, neq, gt, gte, lt, lte, includes, in, notIn, exists, notExists, wildcard)
  4. 1.6Scope targets: project, skill, agent, or department
  5. 1.7OpenAI Codex adapter (execpolicy + guardian prompt export)
  6. 1.8CLI for validate, check, read, init, install, sync, and list

02 / Three actions

Three words decide.

Every rule in the frontmatter names a capability and one of three actions. The Markdown body says the same thing for people, under three conventional headings.

  1. 2.1Most severe wins. When policies are combined, the runtime returns the most severe decision: deny > require_approval > allow.
  2. 2.2No match. If no rule matches, the default is allow. The engine fails open.
Combining policies: the three decisions in order of severity
RankDecisionWhen combined
1denyWins over both
2require_approvalWins over allow
3allowLeast severe
POLICY.mdExample from the docs
---
name: project-guardrails
description: Hard boundaries for this repo
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

  - capability: package.install
    action: require_approval
    reason: New dependencies need approval

  - capability: npm.test
    action: allow
    reason: Tests can run without approval
---

## Forbidden
- Never commit `.env` files or any file containing secrets
- Never execute obfuscated shell commands

## Ask first
- Adding npm dependencies
- Modifying CI/CD pipelines

## Allowed
- Running `npm run typecheck` and `npm run test`
- Reading project documentation

Each frontmatter rule has a twin in the body: deny under ## Forbidden, require_approval under ## Ask first, allow under ## Allowed.

Rules / From the docs example

The three actions, what each means, its body section and an example rule
ActionMeaningBody sectionExample rule
denyThe agent must not do it.## Forbiddenfile.write when payload.path includes .env
Never write .env or secret files
require_approvalThe agent must ask before doing it.## Ask firstpackage.install
New dependencies need approval
allowThe agent may do it.## Allowednpm.test
Tests can run without approval

03 / Condition operators

A rule applies when its condition holds.

A condition is exactly one of a field test, an and group, or an or group, and a field test uses one of twelve operators.

  1. 3.1Evidence. Twelve condition operators and allow / deny / require_approval are implemented in authorizationEngine.ts (21 tests pass). See Claims & evidence.
  2. 3.2Paths. Conditions read payload.*, constraints.*, requester.* and built-ins such as risk, capability and workerId.
conditionYAML
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: in, values: [frontend, backend] }

A field test, an and group and an or group.

The twelve condition operators, by group
GroupOperators (12)
Comparisoneqneqgtgteltlte
MembershipincludesinnotIn
PresenceexistsnotExists
Patternwildcard

04 / Scopes

Scopes stack. The most severe decision wins.

A policy targets one scope, set by scope in the frontmatter. Scopes stack: a skill policy can be stricter than its project policy, and the runtime combines them with the most severe decision winning.

A skill policy sits beside that skill's SKILL.md and holds its negative boundaries.

  1. 4.1Capability patterns. file.write matches exactly, payment.* matches one segment, * matches every capability.

Frontmatter / Scope fields

Frontmatter fields that set a policy's scope
FieldValuesDefault
scopeprojectskillagentdepartmentproject
appliesToAgent or skill ids; ["all"] means every agent.["all"]
Project + skill, combinedIllustrative
# .policy/POLICY.md  (scope: project)
package.install   require_approval
npm.test          allow

# skills/deploy/POLICY.md  (scope: skill)
package.install   deny

# combined for package.install
deny

Illustrative rules built from the docs example. The skill policy is stricter, so deny wins.

05 / Command reference

Ask the file before you act.

The policy CLI validates, checks, reads, scaffolds, installs, syncs and lists POLICY.md files. Everything it does is also available as a library.

The package is not published to npm yet. Until it is, run the CLI from a clone.

  1. 5.1Not on npm. package.json exists at v0.2.0, but the package is not yet published.
  2. 5.2check returns allow, deny or require_approval and the rule that fired.
shellFrom a clone
$ git clone https://github.com/SidianLabs/POLICY.md.git && cd POLICY.md
$ npm install && npm run build
$ node bin/policy.js --help
shellIllustrative output
$ node bin/policy.js check POLICY.md file.write --payload='{"path":".env"}'
deny  rule file.write
  Never write .env or secret files

$ node bin/policy.js check POLICY.md package.install
require_approval  rule package.install
  New dependencies need approval

$ node bin/policy.js check POLICY.md npm.test
allow  rule npm.test
  Tests can run without approval

Checking the docs example POLICY.md. The commands follow the reference below; the printed output is illustrative.

policy / 7 commands

CLI commands, their usage and what each does
CommandUsageWhat it does
validatepolicy validate <path> [--strict]Checks required fields, valid operators and YAML syntax. With --strict, unknown fields are rejected.
checkpolicy check <path> <capability> [--payload=<json>] [--agent=<id>]Evaluates a capability against a policy without executing anything. Returns the decision and the rule that fired.
readpolicy read <path>Reads and prints the effective policy for a directory.
initpolicy init <project>Scaffolds a POLICY.md with default rules: no secret-file writes, approval for new dependencies, tests allowed.
installpolicy install <owner/repo> [--dest=<dir>]Pulls reusable guardrails from any GitHub repository.
syncpolicy syncRegenerates the AGENTS.md <policy_system> block so agent runtimes pick up current policies.
listpolicy listLists every policy discovered in the working directory.

06 / OpenAI Codex adapter

Export the boundaries to Codex.

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

  1. 6.1toCodexExecpolicy(files) exports Starlark execpolicy rules.
  2. 6.2toCodexGuardianPrompt(files) exports Guardian LLM-judge prompt text.
  3. 6.3Coverage. The adapter covers only command.run and network.* rules; other rule types are silently dropped.
adapters/codexTypeScript
import { toCodexExecpolicy, toCodexGuardianPrompt } from '@sidianlabs/policy/adapters/codex';

const execpolicy = toCodexExecpolicy(manager.list());
const guardianPrompt = toCodexGuardianPrompt(manager.list());

Rules in, by capability / Illustrative

Which rule types reach the Codex exports
CapabilityIn execpolicy and guardianPrompt
command.runExported
network.*Exported
file.writeSilently dropped
package.installSilently dropped
Fig. 2Illustrative

07 / Use cases

Write it down once.

  1. 7.1Forbid agents from writing .env or secret filesdeny
  2. 7.2Require approval before adding new dependenciesrequire_approval
  3. 7.3Distribute reusable guardrails across teams and repos
  4. 7.4Inject policy context into agent system prompts

08 / Status and what it does not guarantee

It does not enforce itself.

Working Specification

POLICY.md is a Working Specification, version v0.2.0, with a working implementation and tests. The authorization engine is implemented in TypeScript with 21 vitest tests passing.

Read in full: the NON-GUARANTEES.md file in the repository, and the lab's non-guarantees and claims pages.

NON-GUARANTEES.md / Summary

Assumptions

  1. A.1A host runtime must call the authorization engine. POLICY.md does not enforce itself.
  2. A.2Write access to the policy file allows modification (no signature verification on installed policies).

Not guaranteed

  1. N.1Default behavior is fail-open (allow when no rule matches).
  2. N.2The OpenAI Codex adapter covers only command.run and network.* rules; other rule types are silently dropped.
  3. N.3The specification is a working draft (v0.2.0), not a finalized industry standard.
  4. N.4The package is not yet published to npm.