Skip to main content

houserules

Natural-language linting. Write your rules in English, let an LLM enforce them.

Today: Python source only (*.py), Google Gemini the only provider.

Some conventions are too subjective for a regex or an AST — "comments should explain why, not narrate what the code does," "user-facing errors should explain what went wrong and how to recover." Write those rules in plain English and houserules enforces them with an LLM.

A detector model flags violations; a verifier pass re-checks each one and drops the false positives. It's advisory by default: reports findings, exits 0, never blocks. Set mode: strict to exit 1 on findings.

Data, privacy & cost

Each run sends your rule text plus the full numbered source of the files it checks to Google's Gemini API. With --base, that's the files containing changed lines — still whole files, not just the changed lines.

On Gemini's unpaid tier, inputs may be used to improve Google's products and may be reviewed by humans; paid-tier inputs are not. Read the Gemini API terms before pointing it at anything sensitive.

Cost and latency are unmeasured so far. Expect roughly a per-PR token estimate in the low thousands and a few seconds to low-tens-of-seconds of latency per run — a ballpark, not a benchmark.

Install

pip install houserules

Create a .env file with a Gemini API key. In a source checkout, start from the tracked example:

cp .env.example .env

The CLI finds the nearest .env from the current directory upward. An already exported GEMINI_API_KEY takes precedence over the file.

Configure

Generate a starter .houserules from your repo's own conventions:

houserules init

...or drop one in by hand. houserules needs a .houserules file at your repo root (JSON or YAML; .houserules.json, .houserules.yaml, and .houserules.yml also work). See .houserules.example.yaml for a full example.

If you pass a single explicit directory path and do not override discovery with --config, houserules walks from the current directory through that target and uses the deepest config it finds. That lets houserules examples/basic-demo/ load examples/basic-demo/.houserules.yaml.

model: gemini-3.1-flash-lite
mode: advisory
paths:
  - src
rules:
  - id: comments-explain-why
    description: >
      Comments should explain intent, rationale, or non-obvious constraints—not
      restate what the code makes clear.
  - id: actionable-error-messages
    description: >
      User-facing error messages should explain what went wrong and how to
      recover without exposing implementation details.

Keep mechanically checkable conventions such as TODO markers, import order, and unused variables in Ruff. Use houserules for conventions that require context or judgment.

The examples/basic-demo/ directory shows the same idea in a runnable miniature. Its README has the exact command and sample findings.

Run

houserules                     # lint the configured default paths (verified)
houserules src/ tests/         # lint specific paths
houserules --skip-verification # detector only, no second-pass verifier
houserules --mode strict       # exit 1 if anything is found
houserules --base main         # lint only lines changed since a git ref
houserules --dry-run           # plan work and count model calls, no API calls

Without GEMINI_API_KEY in the environment or a .env file, houserules prints an error and exits 2 — a missing key is a configuration error, not a quiet skip. For CI, gate the job on a same-repo if: condition so fork pull requests (which have no access to the secret) don't fail; see docs/github-actions.md.

How it works

flowchart LR
    A["📝 Rules + 📄 source"] --> B["🔍 Detector"] --> C["✅ Verifier"] --> D["📢 Report"]
  1. Rules + source go in — your plain-English rules and the files to check.
  2. Detector flags candidate violations.
  3. Verifier (on by default) re-checks each one and drops the false positives.
  4. Report what survives — terminal diagnostics or inline PR annotations.

A surviving finding renders as one path:line:column: rule-id message line:

src/app.py:42:5: comments-explain-why Remove the comment; it restates the assignment below.

(PR annotation screenshot: follow-up.)

Scope to git-changed lines with --base.

Run on pull requests

Lint each PR's changed lines and surface findings as inline annotations on the diff. Copy-paste setup: docs/github-actions.md.

Full command, flag, config, and exit-code reference: docs/cli.md.

Use as a library

The framework depends only on python-dotenv and PyYAML, and is importable directly:

from houserules import Rule, StyleLintConfig, run_advisory_lint

Develop

make install   # uv sync
make test      # pytest
make lint      # ruff

Metadata

Release files for houserules 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for houserules 0.1.1
File Size Uploaded Provenance Actions
houserules-0.1.1.tar.gz 46.2 kB Without provenance Details for houserules-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for houserules 0.1.1
File Interpreter ABI Platform Actions
houserules-0.1.1-py3-none-any.whl Python 3 none any Details for houserules-0.1.1-py3-none-any.whl

Total release size: 87.9 kB

Release files / houserules-0.1.1.tar.gz

Download URL houserules-0.1.1.tar.gz
Size 46.2 kB
Tags Source
SHA-256 checksum
How to use checksums
8d17c661c20209fff23c1cfd7c8020116edbdadf76f5ac89478703f64bb20916
BLAKE2b-256 checksum
How to use checksums
2b5244cf190e421338857c15fdb3e0e99f18442973fadb6fb84ebb7e5e66dcd2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / houserules-0.1.1-py3-none-any.whl

Download URL houserules-0.1.1-py3-none-any.whl
Size 41.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8bd107cdf9042cfb899864ce3981322e4c9a2c1c85edffa7b1d665a2bda60eac
BLAKE2b-256 checksum
How to use checksums
06ae38bd4cc93749e11a80bd9e44c1d1832c0b691d520f09763284185910c35c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for houserules 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page