polici
v1.0.3
Published
Typed, deterministic CI policy engine with an extensible provider system
Downloads
674
Readme
Polici
Polici is a typed policy engine for repositories and pull requests. It lets you express CI rules in a small, readable language and evaluates them against exact repository files, JSON data, proposed changes, GitHub reviews, teams, and status checks.
Policies produce structured diagnostics and evidence, so a failed check explains which rule failed and which files, values, users, or checks caused it.
Install
Install the CLI globally:
npm install --global polici
polici --versionOr pin it in a repository:
npm install --save-dev [email protected]
npx polici --versionPolici currently publishes native packages for:
- macOS arm64 and x64
- Linux arm64 and x64 with glibc 2.36 or newer
The JavaScript library remains platform-neutral and requires Node.js 20 or newer.
Write A Policy
Create ci.pol:
policy "service records" {
services = Files("data/services/**/*.json").as(json)
rule "service IDs are unique" {
for each service in services {
require service.id unique in services.{ id }
}
}
rule "every service has an owner" {
require every services.{ owner != "" }
}
}Validate and run it:
polici lock --file ci.pol
polici validate --file ci.pol
polici check --file ci.polThe generated polici.lock belongs in version control. check and validate never update it.
Use Polici In GitHub Actions
Add .github/workflows/polici.yml:
name: Polici
on:
pull_request:
permissions:
contents: read
pull-requests: read
checks: read
statuses: read
jobs:
policy:
name: Policy
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0
persist-credentials: false
- run: npm install --global --ignore-scripts [email protected]
- env:
GITHUB_TOKEN: ${{ github.token }}
run: polici check --repository . --file ci.pol --lockfile polici.lockPolici reads ci.pol, polici.lock, and custom plugin artifacts from the exact trusted pull-request base commit. It evaluates the exact head tree and verifies GitHub event, repository, base, and head coordinates before running rules.
See the complete working repository at darylcecile/polici-example.
Inspect Pull Requests
Import the built-in GitHub provider:
using "github@1" as Git
policy "pull request" {
changes = Git.changes("**/*")
rule "documentation-only area" {
require every changes.{
path matches "docs/**/*.md" or
path matches "README.md"
}
}
rule "required check passed" {
require Git.check("build", "app:15368") passed
}
}The GitHub provider can expose:
- Exact added, modified, deleted, and renamed files
- Immutable before and after file content
- Pull-request metadata and pinned base/head commits
- Effective approvers using each reviewer's latest decisive review
- Complete organization team membership
- Check runs and commit statuses selected by immutable producer identity
After adding the import, update the lockfile:
polici lock --file ci.polWhat Policies Can Do
Polici supports:
- Repository file selection with anchored
*and**globs - Strict JSON parsing with exact file paths and JSON Pointer evidence
- Local bindings, projections, and nested
for eachloops some,every, andnocollection relations- Unique-value constraints
- Boolean logic, equality, pattern matching, and check-state assertions
- Lazy provider resolution and short-circuit evaluation
- Optional rules for genuinely missing or null external data
- Human-readable and schema-backed JSON reports
- Deterministic exit codes:
0passed,1policy failure,2error
For the complete syntax and semantics, see the language reference.
Create A Custom Plugin
Install Polici in the plugin project:
npm install --save-dev [email protected]Define the contract in plugins/ownership/plugin.ts:
import { definePlugin, type } from "polici/plugin-sdk";
export default definePlugin({
name: "ownership",
version: "1.0.0",
policiApi: 1,
contractMajor: 1,
exports: {
approved: type.function({
parameters: {
owner: type.string({ enum: ["frontend", "platform"] }),
},
returns: type.boolean(),
resolve: "approved",
}),
},
runtime: {
kind: "typescript",
entrypoint: "./runtime.ts",
},
});Implement it in plugins/ownership/runtime.ts:
import { defineRuntime } from "polici/runtime-sdk";
import plugin from "./plugin.ts";
export default defineRuntime(plugin, {
resolvers: {
approved(_context, { owner }) {
return owner === "frontend" || owner === "platform";
},
},
});Build and lock it:
polici-plugin build plugins/ownership/plugin.ts \
--no-manifest \
--out plugins/ownership/runtime
polici lock \
--file ci.pol \
--plugin plugins/ownership/plugin.tsplugin.ts is parsed as declarative static metadata during lock, check, validate, and editor operations; it is not executed. The generated canonical contract is verified against polici.lock. Native runtime artifacts are also exact-byte hash checked before execution.
Use the provider through its policy alias:
using "ownership@1" as Ownership
policy "ownership" {
rule "platform is recognized" {
require Ownership.approved("platform")
}
}Read the plugin SDK guide for entities, lazy fields, methods, capabilities, native runtimes, and WASI runtimes.
Use The JavaScript Library
The root package exports the policy engine:
import { checkPolicy } from "polici";
import { RepositorySnapshot } from "polici/core";
const result = await checkPolicy(`policy "example" { rule "always" { require true } }`, {
repository: RepositorySnapshot.fromEntries([]),
});
console.log(result.exitCode, result.status);Available exports include:
polici: parse, compile, evaluate, and check APIspolici/core: repository, file, change, JSON, glob, and evidence typespolici/language: parser, type checker, and editor helperspolici/plugin-sdk: typed static plugin contractspolici/runtime-sdk: typed runtime resolver definitionspolici/plugin: lower-level manifest, lockfile, wire, protocol, and host APIspolici/github: first-party GitHub provider APIs
See the library API guide for options and result types.
VS Code
Install the polici.polici-language extension or recommend it from the repository:
{
"recommendations": ["polici.polici-language"]
}The extension starts polici lsp --stdio and provides:
- Live parser and type diagnostics
- Completions for core values and locked provider contracts
- Hover documentation
- Function and method signature help
- Semantic syntax highlighting
The LSP reads static, lock-verified plugin contracts and never executes plugin runtimes.
Commands
polici lock Create or verify polici.lock
polici validate Parse and type-check without executing providers
polici check Evaluate every policy rule and produce evidence
polici lsp Start the language server over stdio
polici-plugin Build TypeScript-authored custom pluginsUse polici --help or read the CLI reference for all options and output formats.
