Policy-as-code framework for generating legal agreements from TypeScript.
Early alpha. OpenPolicy is under active development and the API may change. We're actively looking for feedback, contributors, maintainers, and sponsors. If you're using it, open an issue to share what's working, what's broken, or what you'd like to see. If you'd like to sponsor the project, reach out via GitHub.
Define privacy policies, terms of service, and other compliance documents in code — then compile them to HTML, PDF, Markdown, and React components at build time.
| Package | Description |
|---|---|
@openpolicy/sdk |
Public API — definePrivacyPolicy(), defineTermsOfService(), and related types |
@openpolicy/core |
Compilation engine — published to npm as a dependency of sdk and vite |
@openpolicy/vite |
Vite plugin for build-time compilation |
@openpolicy/cli |
CLI tool for generating policy documents |
bun install// privacy.config.ts
import { definePrivacyPolicy } from '@openpolicy/sdk'
export default definePrivacyPolicy({
effectiveDate: '2026-01-01',
company: {
name: 'Acme Inc.',
legalName: 'Acme Incorporated',
address: '123 Market St, San Francisco, CA 94105',
contact: 'privacy@acme.com',
},
dataCollected: {
'Account Information': ['Email', 'Name'],
'Usage Data': ['IP address', 'Browser', 'Pages visited'],
},
legalBasis: 'Legitimate interests and consent',
retention: { 'Account data': '3 years after account closure', 'Usage logs': '90 days' },
cookies: { essential: true, analytics: true, marketing: false },
thirdParties: [{ name: 'Stripe', purpose: 'Payment processing' }],
userRights: ['access', 'rectification', 'erasure', 'portability'],
jurisdictions: ['us', 'eu'],
})Or define terms of service:
// terms.config.ts
import { defineTermsOfService } from '@openpolicy/sdk'
export default defineTermsOfService({
effectiveDate: '2026-01-01',
company: {
name: 'Acme Inc.',
legalName: 'Acme Incorporated',
address: '123 Market St, San Francisco, CA 94105',
contact: 'legal@acme.com',
},
acceptance: { methods: ['using the service', 'creating an account'] },
disclaimers: { serviceProvidedAsIs: true, noWarranties: true },
limitationOfLiability: { excludesIndirectDamages: true },
governingLaw: { jurisdiction: 'Delaware, USA' },
})// vite.config.ts
import { defineConfig } from 'vite'
import { openPolicy } from '@openpolicy/vite'
export default defineConfig({
plugins: [
openPolicy({
configs: ['privacy.config.ts', 'terms.config.ts'],
formats: ['markdown', 'html'],
}),
],
})Policy type is auto-detected from the filename — files containing "terms" compile as terms of service, all others as privacy policy. Pass an explicit type to override:
openPolicy({
configs: [
'privacy.config.ts',
{ config: 'legal.config.ts', type: 'terms' },
],
formats: ['markdown', 'html'],
})The legacy single-config form (config + type) still works unchanged.
// src/privacy-policy.tsx
import privacyPolicy from './policies/privacy-policy.html?raw'
export default function PrivacyPolicyPage() {
return <div dangerouslySetInnerHTML={{ __html: privacyPolicy }} />
}| Field | Type | Description |
|---|---|---|
effectiveDate |
string |
ISO date the policy takes effect |
company |
object |
Legal name, address, contact email |
dataCollected |
Record<string, string[]> |
Categories and fields of collected data |
legalBasis |
string |
e.g. 'Legitimate interests and consent' |
retention |
Record<string, string> |
Data retention periods per category |
cookies |
object |
essential, analytics, marketing toggles |
thirdParties |
array |
Name and purpose of each third-party service |
userRights |
string[] |
e.g. ['access', 'erasure', 'portability'] |
jurisdictions |
Jurisdiction[] |
'us', 'eu', 'ca', etc. |
See the policy.config.ts reference for full field documentation.
| Field | Type | Description |
|---|---|---|
effectiveDate |
string |
ISO date the terms take effect |
company |
object |
Legal name, address, contact email |
acceptance |
object |
Methods by which users accept the terms |
governingLaw |
object |
Jurisdiction whose laws govern the agreement |
eligibility |
object? |
Minimum age and jurisdiction restrictions |
accounts |
object? |
Registration, credential, and termination rules |
prohibitedUses |
string[]? |
List of forbidden activities |
payments |
object? |
Paid features, refund policy, price changes |
disclaimers |
object? |
Disclaimer of warranties |
limitationOfLiability |
object? |
Liability exclusions and cap |
disputeResolution |
object? |
Arbitration, litigation, or mediation |
changesPolicy |
object? |
How users are notified of updates |
See the terms.config.ts reference for full field documentation.
jsx— React component (<PrivacyPolicy />)pdf— Static PDF filemarkdown— Plain Markdown document
Pre-built templates for:
- GDPR (EU)
- CCPA (California)
- Multi-jurisdiction
Use the openpolicy CLI to generate and validate policies outside of a Vite build.
# Interactive setup wizard — privacy policy (default)
openpolicy init
# Interactive setup wizard — terms of service
openpolicy init --type terms
# Compile a privacy policy config
openpolicy generate ./privacy.config.ts --format markdown,html --out ./output
# Compile a terms of service config (auto-detected from filename)
openpolicy generate ./terms.config.ts --format markdown,html --out ./output
# Validate a privacy policy
openpolicy validate ./privacy.config.ts --jurisdiction gdpr
# Validate terms of service (auto-detected from filename)
openpolicy validate ./terms.config.ts| Command | Description |
|---|---|
init [--type privacy|terms] |
Interactive wizard that scaffolds a config file |
generate [config] [--type privacy|terms] |
Compiles the policy to the requested output formats |
validate [config] [--type privacy|terms] |
Validates the policy config |
--format accepts a comma-separated list: markdown, html (default: markdown).
--type is auto-detected from the config filename — files containing "terms" are treated as terms of service configs.
--jurisdiction accepts gdpr, ccpa, or all (default: all, privacy only).
# Install dependencies
bun install
# Install lefthook (pre-commit formatting, pre-push type checking)
bun lefthook install
# Run tests
bun test
# Build packages (produces dist/*.js + dist/*.d.ts)
bun run buildThis repo uses Changesets. To cut a release:
- Run
bun run changesetand describe your change. - Merge to
main— CI opens a "Version Packages" PR automatically. - Merge the PR — CI publishes the updated packages to NPM.
Jamie Davenport 💻 |
James 💻 |
Vish 💻 |
OpenPolicy ships an llms.txt reference. AI assistants (Claude, Cursor, Copilot) can read your codebase and auto-generate policy configurations that reflect your actual data flows and third-party integrations.