Rule Packs¶
A rule pack is an installable bundle of Fathom rules registered under the
fathom.packs entry-point group. Packs are resolved by name, not by
filesystem path, so a third-party pack installed from PyPI loads exactly the way
a shipped one does.
Nautilus ships two packs.
Loading a rule pack¶
In nautilus.yaml:
Or directly, when constructing a router:
from nautilus.core.fathom_router import FathomRouter
from nautilus.rules import BUILT_IN_RULES_DIR
router = FathomRouter(
built_in_rules_dir=BUILT_IN_RULES_DIR,
user_rules_dirs=[],
rule_packs=["data-routing-nist"],
)
Packs load after the built-in rules and after user_rules_dirs. Both shipped
packs join the built-in nautilus-routing module: their rules match against the
same working memory as the built-in routing rules and interleave with them by
salience. A pack that declares its own module does not interleave — CLIPS
runs one module's agenda to exhaustion before moving to the next, so salience
only orders rules within a module.
The shipped pack rules sit at 185 and 180 (denial) and 140 (scope constraint), so a source that cannot be scoped is denied before the scope rule would run, around the built-in saliences listed in Authoring Rules.
Pack layout¶
RulePackLoader scans the package the entry point resolves to and loads, in
order, whichever of these directories exist:
Nothing else is loaded. In particular a hierarchies/ directory is not
read — a pack that ships one is shipping a file the engine never sees.
pack.yaml is descriptive metadata for humans and tooling; the loader does not
read it.
Scoping packs need purpose_field¶
The two shipped scope rules write a row filter, and a pack cannot know which column of your table records the purpose a row may be used for. Declare it on the source:
sources:
- id: patients
type: postgres
purpose_field: intended_use # the column the scope constraint is written against
A source that a scoping pack matches and that declares no purpose_field is
denied, with a denial record naming the source. Fail-closed is deliberate:
the alternative was a constraint written against a guessed column name, which
the adapter reports as an error, or worse, silently applies to the wrong column.
data-routing-nist¶
NIST SP 800-53 access control. Implements AC-6 (least privilege, emits a
scope_constraint binding confidential-and-above sources to the agent's stated
purpose, and denies such a source when it declares no purpose_field) and
AC-16 (security attributes, denies a source carrying no classification label).
Other controls the pack previously advertised are not implemented, because their conditions cannot be expressed over the facts the broker asserts. See the pack README for the control-by-control reasons.
data-routing-hipaa¶
HIPAA Privacy Rule constraints. Implements minimum necessary (45 CFR 164.502(b),
scoping PHI to the stated purpose and denying a PHI source that declares no
purpose_field) and the treatment/payment/operations purpose limitation
(45 CFR 164.506).
Writing a pack¶
Declare the entry point in your pyproject.toml:
my_package.my_pack must be an importable package (it needs an __init__.py)
whose directory holds the rules/ subdirectory above, and your build backend
must be configured to include the YAML in the wheel — for setuptools:
A pack that points at a non-importable module, or whose YAML is left out of the wheel, fails at load time rather than at install time.
Compliance disclaimer¶
Both shipped packs are reference implementations only — they are not certified for production compliance. Organizations must validate rules against their specific regulatory requirements and engage qualified compliance personnel.