Skip to content

Runtime Engine

Policies are Markdown files, but enforcement happens in code. The runtime loads every POLICY.md in scope, evaluates intents against all of them, and returns the most severe decision.

Note: the @sidianlabs/policy package is not on npm yet — run the CLI from a clone (npm install && npm run build, then node bin/policy.js).

The pieces

ModuleFileJob
PolicyManagersrc/policyManager.tsDiscovers, loads, and lists policies
AuthorizationEnginesrc/authorizationEngine.tsEvaluates one intent against one policy set
PolicyValidatorsrc/validate.tsSchema, operator, and YAML checking
Installersrc/installer.tsPulls policies from GitHub repos
AgentsMdsrc/agentsmd.tsRegenerates the AGENTS.md policy block
Parsersrc/parser.tsFrontmatter + Markdown body parsing
Codex adapterssrc/adapters/codex.tsExports to OpenAI Codex formats

Load and evaluate

typescript
import { createPolicyManager } from '@sidianlabs/policy';

const manager = createPolicyManager();
manager.load(); // searches working dir for POLICY.md files

const engine = manager.createAuthorizationEngine();
const decision = engine.evaluate({
  id: '1',
  workRunId: 'run-1',
  workerId: 'agent-1',
  specialist: 'frontend',
  actionType: 'tool',
  capability: 'file.write',
  riskLevel: 'medium',
  payload: { path: 'src/.env' },
  requester: { type: 'user', id: 'user-1' },
  createdAt: Date.now(),
});

// decision.action === 'deny'
// decision.reason === 'Never write .env or secret files'

Inject into system prompts

Policies double as LLM context - the agent reads the same rules the engine enforces:

typescript
import { buildPoliciesContext } from '@sidianlabs/policy';

const prompt = buildPoliciesContext(manager);
// prepend to the agent system prompt

Composite engines

Stack an org policy over a repo policy. The composite returns the most severe decision across every engine:

deny > require_approval > allow
typescript
import { createCompositeAuthorizationEngine, createAuthorizationEngine } from '@sidianlabs/policy';

const filePolicyEngine = manager.createAuthorizationEngine();
const orgPolicyEngine = createAuthorizationEngine({ document: orgPolicy });
const final = createCompositeAuthorizationEngine([orgPolicyEngine, filePolicyEngine]);

const result = final.evaluate(intent);

Validation

PolicyValidator checks required fields, valid operators, and YAML syntax. With --strict, unknown fields are rejected:

bash
npx @sidianlabs/policy validate POLICY.md --strict

Distribution: install and sync

bash
# Pull a team's guardrails into .policies/
npx @sidianlabs/policy install SidianLabs/payment-guardrails

# Regenerate the AGENTS.md <policy_system> block
npx @sidianlabs/policy sync

# See every discovered policy
npx @sidianlabs/policy list

OpenAI Codex adapters

Export policies to the formats Codex understands:

typescript
import { toCodexExecpolicy, toCodexGuardianPrompt } from '@sidianlabs/policy/adapters/codex';

// Starlark execpolicy for the Codex runtime
const execpolicy = toCodexExecpolicy(manager.list());

// Guardian prompt text for the Codex harness
const guardianPrompt = toCodexGuardianPrompt(manager.list());

Scope stacking

Discovery order is project, then named directories (.policies/payment/), then skill-local files (.devin/skills/<skill>/POLICY.md). A skill policy can be stricter than its project policy; evaluation combines all in-scope policies with most-severe-wins, so a skill-local deny always beats a project-level allow.

Released under the Apache 2.0 License.