Custom Rules
RuleContext and compiler facts
Inspect stable compiler-owned facts and opt into lazy SQL AST access.
RuleContext exposes typed, read-only views over the compiled project:
ctx.sql: authored and expanded SQLctx.graph: compiler-resolved dependencies and dependentsctx.columns: declared and inferred output columnsctx.contracts: enforcement and grain factsctx.testsandctx.audits: checks associated with a modelctx.declarations: public and model-scoped enums and constantsctx.project: compiled resources and deterministic project-tree observations
Authored and expanded SQL
Section titled “Authored and expanded SQL”Choose the SQL representation that matches the requirement:
sql = ctx.sql.for_model(model)
authored_text = sql.authored.sourceexpanded_text = sql.expanded.sourceAn authoring convention may inspect what a developer wrote. A compiler-output convention may need the expanded SQL after interpolation, declarations, and macros.
Common SQL structures
Section titled “Common SQL structures”Common structures are available through typed source nodes:
for cte in sql.expanded.ctes(): ...
for star in sql.authored.star_projections(): ...Lazy Polyglot access
Section titled “Lazy Polyglot access”Use the full Polyglot AST only when common projections are insufficient:
ast = sql.expanded.polyglot_ast()for node in ast.walk(): ...AST construction is lazy. A path or contract Rule does not pay for SQL parsing merely because AST access exists elsewhere.
Project structure
Section titled “Project structure”Use the compiler-owned tree rather than direct filesystem calls:
parts = ctx.project.tree.relative_parts(path=model.path, under="models")models = ctx.project.tree.resources_under("models/orders")config = ctx.project.tree.read_text("rules/requirements.yaml")Paths remain project-relative, and observations participate in cache invalidation.
Choose the subject deliberately
Section titled “Choose the subject deliberately”A model-subject Rule is evaluated and cached per model. A project-subject Rule runs once and can
iterate ctx.project.models. Use a project subject only when the invariant genuinely needs a
project-wide view; its cache invalidation is intentionally broader.