Rule Libraries

Version: v0.104.0
Foundation: plans/expert-system.md §5

A rule library is a versioned, distributable package of Datalog inference rules and SHACL validation shapes. Libraries allow teams to share domain-specific reasoning logic — patient-matching rules, anti-money-laundering patterns, supply-chain constraints — without each team re-implementing the same logic from scratch.

Rule libraries are analogous to npm packages or pip packages, but for knowledge-graph reasoning.


Library Format

A rule library is a single Turtle (.ttl) file with the following structure:

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix pg: <http://pg-ripple.org/lib/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

# ── Required: library declaration ────────────────────────────────────────────

<urn:my-org:my-library> a pg:RuleLibrary ;
    dcterms:title       "my-library" ;
    dcterms:description "Human-readable description of what the library does." ;
    dcterms:license     <https://spdx.org/licenses/MIT.html> ;
    owl:versionInfo     "1.2.0" ;

    # ── Optional: dependencies ───────────────────────────────────────────────

    # Declare another library as a dependency (its URL or local path).
    pg:dependsOn <https://example.org/shared-library.ttl> ;

    # ── Optional: Datalog rules ──────────────────────────────────────────────

    pg:rules """
        ?x <https://schema.org/ancestor> ?z :-
            ?x <https://schema.org/parent> ?z .

        ?x <https://schema.org/ancestor> ?z :-
            ?x <https://schema.org/parent> ?y ,
            ?y <https://schema.org/ancestor> ?z .
    """ .

# ── Optional: SHACL shapes ────────────────────────────────────────────────────

<https://my-org.example/shapes/PersonShape>
    a sh:NodeShape ;
    sh:targetClass <https://schema.org/Person> ;
    sh:property [
        sh:path <https://schema.org/name> ;
        sh:minCount 1 ;
        sh:datatype <http://www.w3.org/2001/XMLSchema#string> ;
    ] .

Required metadata triples

All four of these triples must appear on the pg:RuleLibrary subject:

PropertyValue
dcterms:titleShort identifier used as the library name in the catalog (plain string)
dcterms:descriptionHuman-readable explanation of what the library does
dcterms:licenseSPDX license IRI (see License requirements)
owl:versionInfoVersion string (e.g. "1.2.0")

Optional triples

PropertyValue
pg:rulesxsd:string literal containing one or more Datalog rule bodies
pg:dependsOnIRI of a dependency library (URL or local path); can appear multiple times
SHACL shapesAny sh:NodeShape / sh:PropertyShape resources in the same file

Installing a Library

-- Install from a local file (absolute path):
SELECT pg_ripple.install_rule_library('/opt/pg_ripple/libraries/my-library.ttl');

-- Install from an HTTPS URL:
SELECT pg_ripple.install_rule_library(
    'https://libraries.example.org/my-library-1.2.0.ttl'
);

install_rule_library returns the library name on success.

Idempotency: re-installing the same name + version is a no-op. The function returns the name without error or duplication.

Accepting non-permissive licenses

If a library carries a non-permissive license (anything other than MIT, Apache-2.0, or the PostgreSQL License), you must explicitly acknowledge this:

SELECT pg_ripple.install_rule_library(
    '/opt/libraries/gpl-library.ttl',
    accept_license => true
);

Without accept_license => true, install_rule_library raises PT0455 and exits without loading the library.


Listing Installed Libraries

SELECT * FROM pg_ripple.list_rule_libraries();
ColumnTypeDescription
nameTEXTLibrary identifier (from dcterms:title)
versionTEXTVersion from owl:versionInfo
installed_atTEXTTimestamp of installation
descriptionTEXTLibrary description
license_iriTEXTSPDX license IRI

Upgrading a Library

SELECT pg_ripple.upgrade_rule_library('my-library');

upgrade_rule_library re-fetches the library from its original source_url, replaces all installed rules and shapes, and updates the version in the catalog.

PT0456: If another installed library depends on my-library, the upgrade is rejected — uninstall the dependent library first.


Uninstalling a Library

SELECT pg_ripple.uninstall_rule_library('my-library');

This removes:

  • All Datalog rules for the library's rule set name.
  • All SHACL shapes loaded from the library's Turtle file.
  • The catalog row in _pg_ripple.rule_libraries.

PT0456: Rejected when another installed library declares my-library as a dependency. Uninstall the dependent library first.


REST API

The pg_ripple_http companion service exposes a read-only endpoint:

GET /rule-libraries
Authorization: Bearer <token>

Returns a JSON array of installed library objects:

[
  {
    "name": "my-library",
    "version": "1.2.0",
    "installed_at": "2026-05-10 12:00:00",
    "description": "Human-readable description.",
    "license_iri": "https://spdx.org/licenses/MIT.html"
  }
]

Dependency Resolution

Dependencies declared with pg:dependsOn are resolved recursively in topological order: dependency libraries are installed before the library that requires them.

Constraints:

  • Dependency graphs must be acyclic. Cycles raise PT0453.
  • Only single-version dependencies are supported — no semver ranges.
  • If a declared dependency URL cannot be fetched, PT0454 is raised.

License Requirements

pg_ripple distinguishes permissive from non-permissive licenses:

LicenseSPDX IRIAuto-accepted
MIThttps://spdx.org/licenses/MIT.html✅ Yes
Apache-2.0https://spdx.org/licenses/Apache-2.0.html✅ Yes
PostgreSQL Licensehttps://spdx.org/licenses/PostgreSQL.html✅ Yes
Any other❌ Requires accept_license => true

Operator responsibilities

Before installing a library with accept_license => true:

  1. Read the license text at the SPDX IRI.
  2. Consult your legal team if the library will be used in a commercial product or distributed as part of a service.
  3. Document the accepted license decision in your change-management log.
  4. Review the library content — pg_ripple does not audit library rules for correctness, safety, or regulatory compliance.

pg_ripple does not provide legal advice. The accept_license flag is a technical confirmation mechanism, not a legal guarantee.


SSRF Protection

URL-based library sources are validated against the federation SSRF allowlist before any network request is made. The check follows the same policy as SERVICE endpoints in SPARQL queries:

  • default-deny (default): blocks RFC-1918, loopback, link-local addresses.
  • allowlist: only URLs listed in pg_ripple.federation_allowed_endpoints.
  • open: no restrictions (development/testing only).

A blocked URL raises PT0452.


Authoring a Library

1. Write the Turtle file

Follow the Library Format above. Rules must be valid pg_ripple Datalog syntax — test them with pg_ripple.load_rules() first.

2. Validate locally

# Test rule syntax:
psql -c "SELECT pg_ripple.load_rules(\$\$<rules here>\$\$, 'test')"

# Test install from local path:
psql -c "SELECT pg_ripple.install_rule_library('/path/to/my-library.ttl')"

# Verify it appears in the catalog:
psql -c "SELECT * FROM pg_ripple.list_rule_libraries()"

# Uninstall after testing:
psql -c "SELECT pg_ripple.uninstall_rule_library('my-library')"

3. Publish

Rule libraries can be published:

  • As files on an HTTPS server.
  • As GitHub releases with raw URLs.
  • As OCI artifacts or Helm config maps (for Kubernetes deployments).

There is no central registry — operators install from any URL or local path they trust.

4. Versioning

Use semantic versioning (MAJOR.MINOR.PATCH) in owl:versionInfo. When you release a new version, update the Turtle file and re-publish. Users upgrade with upgrade_rule_library().


Error Reference

CodeWhenMessage
PT0452URL blocked by SSRF allowlistinstall_rule_library: URL '...' is blocked by the SSRF allowlist
PT0453Circular dependency detectedinstall_rule_library: dependency cycle detected involving library '...'
PT0454Dependency URL unreachableinstall_rule_library: dependency '...' could not be fetched
PT0455Non-permissive license, no acceptanceinstall_rule_library: library '...' uses license '...' — set accept_license => TRUE
PT0456Dependent library prevents actionupgrade/uninstall_rule_library: library '...' is required by '...' — uninstall the dependent first
PT0459Name conflicts with a built-in bundleinstall_rule_library: name '...' conflicts with a built-in bundle

Relationship to Built-in Bundles

pg_ripple ships with several built-in bundles (SKOS, OWL RL, RDFS, DCTERMS, Schema.org, FOAF) accessible via load_datalog_bundle() and load_shape_bundle(). These are compiled into the extension binary.

External rule libraries (this feature) are the user-extensible counterpart: they are Turtle files loaded at runtime and stored in the _pg_ripple.rule_libraries catalog.

The two systems coexist. A rule library may declare a built-in bundle as a dependency using pg:dependsOn "skos"install_rule_library will activate the bundle via load_datalog_bundle() before loading the library's own rules.

Library names that collide with built-in bundle names are rejected with PT0459.