r14n : compliance controls :: i18n : strings
r14n is the home of the Regulatory Localization Pack Specification (RLPS) — an open, human-readable, machine-readable format for expressing which compliance controls are required for a given (regulatory-profile × jurisdiction × subject), with a fail-closed default, a posture selector, and legal-review provenance.
▶ Watch the explainer video — the i18n analogy, the fail-closed resolver, and the counsel-gating model in plain language, before the spec makes them precise.
Where i18n maps locales/<lang>/<feature>.toml → localized strings, RLPS maps
packs/<profile>/<domain>.r14n.toml → required controls. A translation key is a stable id
for a user-facing string; an RLPS control key is a stable id for a required compliance action.
i18n: translation key → localized string locales/<lang>/<feature>.toml
r14n: control key → required / prohibited packs/<profile>/<domain>.r14n.toml
RLPS is a data-interchange and configuration standard, not legal counsel. A pack is a
machine-readable template of controls; it does not tell you what the law is, and selecting a
posture that under-restricts a jurisdiction's law is the consuming operator's responsibility.
"aggressive" ≠ "compliant." See docs/not-legal-advice.md.
Whether you may record a meeting — and what you must do first (get consent, show an on-screen indicator, announce an AI notetaker, …) — depends on where everyone is and what kind of recording it is. Today that logic is usually buried in application code: hard to audit, easy to get subtly wrong, and impossible for a compliance officer to review without reading source.
This is a measured problem, not a hypothetical. US recording-consent law alone splits three ways
(38 one-party states + DC, 11 all-party states, one with no wiretap statute — 12 Harv. L. & Pol'y
Rev. 177). A think-tank estimate puts the US state privacy patchwork at $98–112B/year in
projected out-of-state compliance costs (ITIF 2022), the FCA/Bank of England pilots found
inconsistent interpretation of regulations is the single biggest cost driver of manual
compliance, and the AI era is multiplying the surface: state AI laws grew from 1/year (2016) to
131/year (2024) (Stanford HAI AI Index). Full annotated bibliography — 28 verified sources — in
docs/secondary-sources.md.
# BEFORE — jurisdiction rules tangled into app code (pseudocode, any language)
if any(participant in a two-party-consent state):
require(consent)
else if any(participant in the EU):
if ai_notetaker: require(announcement)
require(consent)
# …dozens more brittle branches — invisible to a compliance reviewer, easy to get subtly wrong
# AFTER — the same rules as a reviewable pack: recording_consent.r14n.toml
[subject.twin_attend]
controls = ["announcement", "aph_mandate_principal_signed"]The app stops deciding and just enforces what the resolver returns.
RLPS pulls those rules out of the code into packs — small, human-diffable TOML files that map a
(profile × jurisdiction × subject) to the set of compliance controls required. An app asks a
resolver "given who's involved and where, what's required right now?" and gets back a control
set plus a signed, machine-readable receipt proving which pack drove the decision and who
attested it. The resolver fails closed: if a pack is missing, malformed, expired, or the
jurisdiction is ambiguous, it demands everything the app can enforce and loudly flags the
fallback — it never silently under-restricts.
The seven pieces (spec §2): a control (one required action, a stable key), a domain
(regulated activity, e.g. recording_consent), a subject (the discriminator within a domain,
e.g. a recording rail), a profile (<regime>/<jurisdiction> tag), a pack (one
<domain>.r14n.toml for one profile), a decision (the resolver's output), and provenance
(the pack's legal-review block + a signed decision receipt).
A pack a compliance officer and an engineer can both read and review in a PR. The posture
selector (strictness) chooses which table governs; [legally_required] is the fail-closed floor.
[meta]
strictness = "aggressive" # posture — NOT a legal ordering; "aggressive" ≠ "compliant"
[meta.legal_review]
status = "not_required" # this baseline over-restricts; it can never under-restrict
[subject.telepresence]
controls = ["signal_notice", "indicator_mount", "aph_mandate_principal_signed"]
[subject.twin_attend]
controls = ["announcement", "aph_mandate_principal_signed"]
[legally_required] # the floor: required under the `minimal` posture / as a catch-all
controls = ["attestation", "signal_notice", "indicator_mount", "announcement", "aph_mandate_principal_signed"]A pack may also declare [prohibited] (controls no posture may add — the data-minimization guard),
inherits (a parent profile it deltas from), and an effective_from/effective_until envelope.
Rust — build a query and resolve the required controls (click to expand)
use std::collections::BTreeSet;
// The caller declares EVERY control it can enforce — the aggressive/fallback ceiling.
let universe: BTreeSet<r14n::ControlKey> =
["attestation", "signal_notice", "indicator_mount", "aph_mandate_principal_signed"]
.into_iter().map(|s| r14n::ControlKey(s.into())).collect();
let query = r14n::RegulatoryQuery {
domain: "recording_consent".into(),
profile: r14n::RegulatoryProfile("aggressive".into()), // selects packs/aggressive/
jurisdiction: "all_party".into(),
subject: "telepresence".into(),
universe,
as_of: Some("2026-07-08".into()), // enables the effective-date check
};
// Load packs from a directory laid out like locales/: <root>/<profile>/<domain>.r14n.toml
let adapter = r14n::TomlRegulatoryPolicyAdapter::new("packs".into(), None);
let decision = r14n::RegulatoryPolicyPort::required_controls(&adapter, &query);
// decision.required — the controls the caller MUST satisfy (⊆ universe)
// decision.verdict — Permit | Block
// decision.provenance — pack source, review status, fell_back, advisory-only taint
assert!(decision.required.contains(&r14n::ControlKey("indicator_mount".into())));The port is infallible: a missing/malformed/expired/floor-less pack returns
aggressive-over-universe with provenance.fell_back = true, never an empty set.
JS/TS and Python — the same resolver, generated from the Rust core (click to expand)
Both packages are generated from resolver/ — wasm-bindgen for JS/TS, a PyO3 abi3 wheel for
Python — so they are the same decision logic, not re-implementations. Neither has runtime
dependencies. There is no filesystem in wasm, so packs are passed in as a JSON object mapping
"<profile>/<domain>.r14n.toml" to the pack's TOML text (the same layout as on disk).
$ npm install @squillo/r14n # https://www.npmjs.com/package/@squillo/r14n
$ pip install r14n # https://pypi.org/project/r14n/import { resolve } from "@squillo/r14n";
const decision = JSON.parse(resolve(JSON.stringify(packs), JSON.stringify(query)));
decision.provenance.fell_back; // true ⇒ NO reviewed pack governed this decisionimport json, r14n
decision = json.loads(r14n.resolve(json.dumps(packs), json.dumps(query)))resolve_with_receipts additionally returns both serialized receipt forms (TS 27560 + DPV
JSON-LD, and the Kantara CR v1.1 shim). Fail-closed behavior is identical in every host; a
caller's malformed JSON throws/raises instead, so a bug is never mistaken for a policy
fallback.
$ r14n extract --catalog catalog/recording_consent.catalog.toml --profile gdpr/eu # scaffold a pack
$ r14n validate packs/aggressive/recording_consent.r14n.toml \
--catalog catalog/recording_consent.catalog.toml # lint it
$ r14n keygen --out reviewer # Ed25519 keypair
$ r14n sign packs/aggressive/recording_consent.r14n.toml --key reviewer.seed # attest it
$ r14n verify packs/aggressive/recording_consent.r14n.toml --directory registry/directory.json \
--as-of 2026-07-08 --jurisdiction US-CA # + check the signer is a trusted reviewer
$ r14n publish packs/aggressive/recording_consent.r14n.toml --id aggressive/recording_consentmerge is the gettext-msgmerge analogue: when the catalog changes it flags only the changed
controls for legal re-review, preserving the reviewed pack byte-for-byte.
Every decision can be serialized as a signed, machine-readable receipt — audit evidence of what was decided, by which pack, and whether provenance was verified.
JSON — a decision receipt (trimmed; click to expand — full example)
advisory_only stays true until a signature from a directory-listed, non-revoked reviewer is
verified — a self-declared legal_review.status = "approved" never clears it on its own.
When an AI agent — a "twin" — records or attends on a person's behalf, the question isn't only
may this be recorded here but is this agent authorized to act for this human at all. RLPS
carries that as first-class controls on the delegate/twin rails (twin_attend, telepresence),
and it carries two of them, because APH — Agent-Per-Human
notarization, Squillo's protocol extending Google's A2A and AP2 — distinguishes two trust
models that are not interchangeable:
aph_mandate_principal_signed— the human's own key signed this act. Consent, cryptographically.aph_mandate_notary_attested— a notary asserts the human authorized it. Provenance, not consent; the human's key never touched the envelope.
One key satisfiable by either would record that something authorized the act while concealing
whether a human ever signed anything — so a pack that gates consent requires the principal-signed
key and refuses the downgrade. Squillo's aggressive baseline requires it on every rail. Neither
key supplies any other participant's consent: a mandate authorizes an agent to act for its
own principal, which is what attestation / announcement / signal_notice are for.
RLPS interoperates with APH — it defines what satisfies a control and cites APH for how to
verify one; it does not define, restate, or implement the protocol, and the reference resolver
deliberately links no APH code (prescription and verification are different jobs). The contract,
including revocation semantics and what an enforcement gate must record, is in
docs/aph-integration.md. Still NOT legal advice.
v0.1 — draft. Reference-implementation-first. This repository is the working existence proof; a twin of the resolver already ships inside Squillo OS as its regulatory-policy engine — the live first consumer.
spec/RLPS-v0.1.md— the normative specification (conflict rules, trust-root, temporal split, interop mappings).schema/— JSON Schema for.r14n.tomlpacks + the decision-receipt schema (receipt.schema.json; mapping to TS 27560 indocs/receipt-27560-mapping.md).ns/— the published RLPS vocabulary: the@context(context.jsonld) + SKOS/RDFS term definitions (rlps.ttl), so thehttps://r14n.squillo.com/ns#namespace resolves.catalog/— the canonical CONTROL CATALOG (control keys + deontic kind + facets).resolver/— the Rust reference resolver (embeddable crate; runcargo test) including thereceiptmodule: ISO/IEC TS 27560-structured + W3C DPV JSON-LD decision receipts + a Kantara CR v1.1 shim (namespace; worked AI-Act §50 example). Fail-closed everywhere; receipts areadvisory_onlyuntil provenance is cryptographically verified.packs/— Squillo's ownaggressive+minimalposture baselines (NOT jurisdiction claims) + a fictionalexample/regionpack that demonstrates the<regime>/<jurisdiction>profile grammar (also NOT a jurisdiction claim).conformance/— language-neutral JSON test vectors for the 3 conformance levels.tools/— ther14npack-lifecycle CLI:extract/merge/validate/keygen/sign/verify/publish. Signatures bind the pack's<profile>/<domain>identity (not just its bytes);verify --directorychecks the signer against a reviewer-key directory (revocation + expiry + jurisdiction);publishwrites a local content-addressed index.registry/— reviewer-key directory + pack-index schemas (trust root, versioning, supersession).bindings/— the JS/TS and Python packages, generated fromresolver/:bindings/wasm(wasm-bindgen shim →@squillo/r14non npm, built bybindings/npm/build.mjs) andbindings/python(PyO3 abi3 shim →r14non PyPI, built by maturin). Both are thin FFI shims over one tested JSON boundary (resolver/src/wire.rs) — not ports, so there is nothing to drift.site/— the r14n.squillo.com Worker: the splash page and the vocabulary namespace host (/ns), which serves thens/artifacts byte-identical by importing them directly at bundle time.r14n Spec/+baselines/+snapp/— the RLPS specification expressed as an N Lang Snapp (typed, machine-checkable spec sources), a baseline-pack consumer Snapp, and the emitted ABI bundle other Snapps consume. The Snapp sources are Apache-2.0 like the code; N Lang itself (language, compiler, runtime, Snapp tooling) is proprietary to Squillo, Inc. and not required to use RLPS — the markdown spec inspec/is the normative text, and where the two disagree,spec/wins.GOVERNANCE.md— reference-impl-first staging, federated-with-attestation ownership, SDO entry criteria.CONTRIBUTING.md(issue-first RFC process, DCO + pack gate),CODE_OF_CONDUCT.md,CHANGELOG.md,TRADEMARKS.md(name + conformance-claim usage),SECURITY.md+docs/key-management.md(crypto threat surface + key hygiene),docs/receipt-data-handling.md(receipts carry PII),docs/secondary-sources.md(the 28-source annotated evidence annex: fragmentation cost + AI-era amplification + policy-as-code lineage),docs/wiretap-us-dossier.md(secondary-source research memo for the counsel-gatedwiretap/usengagement — no pack, no legal conclusions), anddocs/audits/(the standing council-audit reports).- CI:
.github/workflows/gates.ymlruns both test suites (which include the schema-vs-producers conformance tests intools/tests/schema_conformance.rs), lints the shipped packs, and gates on sanitization (no internal references in tracked files), clippy (warnings-as-errors), the declared MSRV (1.85), and DCO sign-off on PRs. Rust only — no Python.
Deliberately NOT here yet (held for licensed counsel): real jurisdiction packs
(wiretap/us 50-state matrix, gdpr/eu, ccpa-cpra/us/ca, …). Any pack claiming a real
jurisdiction MUST carry a reviewing_attorney_of_record + bar number and be attested by licensed
counsel — see the spec §Governance and the counsel gate in GOVERNANCE.md.
Coding agents get RLPS as a first-class skill rather than a re-read of the spec. One knowledge
source serves both ecosystems: skills/spec/SKILL.md is written in the
open Agent Skills format, AGENTS.md is the agents.md-convention
entry point (Codex and others) carrying orientation plus the invariants that must not break, and
.claude-plugin/ packages the same skill with slash commands
(/validate, /resolve,
/conformance).
/plugin marketplace add squillo/r14n
/plugin install r14n@r14n-rlpsThe pack teaches the fail-closed rule, the advisory-only taint, and the governed conformance-claim wording — and it refuses to author a real-jurisdiction pack, because those are counsel-gated.
RLPS is not the first attempt to make compliance machine-readable — see the related work in the
spec (NIST OSCAL, W3C DPV / ISO 27560, Policy Cards, LegalRuleML, OPA/Cedar), and it sits in a
recognized institutional lineage: governments themselves publish and pilot machine-consumable
rules (OECD "Rules as Code"; the FCA/Bank of England machine-executable-regulation pilots; FSB
suptech; BIS embedded supervision — spec §11 and docs/secondary-sources.md §V).
RLPS occupies one specific, un-owned layer: the control-prescription layer, authored in
i18n-ergonomic TOML a compliance officer and an engineer can diff in a PR, with an
RFC-4647-style jurisdiction-negotiation algorithm and a fail-closed floor. It interoperates with
those standards rather than replacing them.
Dual: the spec text, catalog, and schemas are CC BY 4.0; the reference resolver and
tooling code are Apache-2.0. See LICENSE (code) and LICENSE-SPEC (docs).
Squillo, Inc.

{ "@type": "rlps:ControlDecisionReceipt", "processing": { "domain": "recording_consent", "subject": "twin_attend", "operations": ["rlps:AudioRecording", "rlps:VoiceRecording"] }, "jurisdiction": { "dpv:hasJurisdiction": ["DE"], "attribution_source": "operator_declared" }, "decision": { "verdict": "permit", "posture": "aggressive", "required_controls": ["ai_disclosure", "announcement", "attestation", …] }, "provenance": { "advisory_only": true, "provenance_verified": false, "fell_back": false }, "ai_disclosure": { "disclosed_at": "2026-08-02T08:59:00Z", "method": "in_meeting_announcement" }, "disclaimer": "NOT LEGAL ADVICE. …" }