Skip to main content

precommitEU

precommitEU

Catch EU regulatory violations at PR time, on your own machine, with zero data egress.

One local scanner, eight EU regulations: GDPR, the EU AI Act, NIS2, DORA, the Cyber Resilience Act, the Digital Services Act, the Digital Markets Act and the Data Act.

Documentation  ·  Install  ·  CLI reference  ·  Model bundle  ·  precommit.eu

precommitEU scanning a Python project for GDPR violations

A real scan, unedited: about 80 seconds on an M-series MacBook, played back at 5×. models.py holds only a dataclass, so the detector clears it and the validator is never called. user_store.py mentions a sibling file, so the orchestrator takes over: it resolves UserProfile into models.py, finds that audit_line() interpolates a national ID and a home address, and confirms a GDPR Art. 32 violation on a log line that looks harmless on its own. Grep cannot find that one.

Replay this scan in your browser. No install, nothing to upload.

export PRECOMMITEU_MODELS_DIR=~/.precommiteu/models
precommiteu scan src/ --fail-on-findings

The Zen of EU Code

  1. Put purpose before collection.
  2. Collect less than you could, and keep it for less time.
  3. Let people know what the system knows.
  4. Make consent a choice, not a trap.
  5. Give people working controls over their data.
  6. Protect what you keep, from design to update.
  7. Children deserve stronger defaults.
  8. Explain automated decisions before they become consequences.
  9. Build systems that fail safely, recover clearly, and report harm responsibly.
  10. Make switching, portability, and interoperability real.

Run precommiteu this to print it.

Quick start

brew install llama.cpp
pip install precommiteu "huggingface_hub[cli]"
hf download AlexandruGirlea/precommiteu-models base.gguf gdpr/detector-adapter.gguf --local-dir ~/.precommiteu/models
export PRECOMMITEU_MODELS_DIR=~/.precommiteu/models
precommiteu scan src/

Linux, source and GPU builds, downloading more packs, air-gapped installs and uninstall: Installation.

hf download writes the bundle in the layout the scanner expects. Each adapter must sit in a directory named exactly after its pack, because the scanner resolves <models-dir>/<regulation>/detector-adapter.gguf:

~/.precommiteu/models/
├── base.gguf                        # shared by every regulation
├── gdpr/detector-adapter.gguf
└── eu_ai_act/detector-adapter.gguf  # one directory per pack you downloaded

A flat directory does not work: a missing adapter is not an error, the scan just continues on the base model alone in degraded mode and logs a warning.

precommiteu scan src/ --regulations gdpr,eu_ai_act    # several regulations
precommiteu scan --ci --fail-on-findings              # changed files only, gate the build

From Python

import os
from precommiteu import scan_paths

# Required unless you pass orchestrator_model_path / detector_adapter_path
# explicitly. Without it, scan_paths raises ValueError.
os.environ["PRECOMMITEU_MODELS_DIR"] = "~/.precommiteu/models"

result = scan_paths(["src/"], regulations=("gdpr",))
for finding in result.findings:
    print(finding.regulation, finding.file,
          finding.probable_article_id, finding.description)

Full API reference, every parameter, the result schemas and streaming callbacks: Python library.

How it works

  • Your code never leaves your machine. All analysis runs on local llama-server processes the scanner starts and stops itself. No cloud, no telemetry, no network egress.
  • No finding without proof. A detector proposes candidates; a validator then has to locate the quoted evidence verbatim in your file, or the candidate is dropped. Confirmed findings cite the line. Candidates that fail validation are reported as advisories: clearly labeled, never gating. Only confirmed findings can fail a build.
  • Deterministic where it matters. Grammar-constrained model output, fixed budgets per file, suppression rules with auditable reasons.

Model bundle

precommitEU ships as two artifacts. The scanner is a pure-Python wheel on PyPI; the weights are published separately on Hugging Face at AlexandruGirlea/precommiteu-models (public, no token needed). pip install does not fetch them.

The repository holds seven files: one shared 4.36 GiB base.gguf used by every regulation, plus a 77 MiB detector adapter per pack. You choose which adapters to download. Name the files you want, or omit them to take everything:

# base + GDPR only, about 4.5 GB
hf download AlexandruGirlea/precommiteu-models base.gguf gdpr/detector-adapter.gguf --local-dir ~/.precommiteu/models

# add another pack later, the base is already there
hf download AlexandruGirlea/precommiteu-models eu_ai_act/detector-adapter.gguf --local-dir ~/.precommiteu/models

# everything, about 4.9 GB
hf download AlexandruGirlea/precommiteu-models --local-dir ~/.precommiteu/models

--regulations then picks which of the downloaded packs to run. The two are independent, and that is worth knowing: scanning with a regulation whose adapter you never downloaded is not an error. The run continues on the base model alone in degraded mode, logs a warning, and detects noticeably less. If a scan seems weak, check the adapter is actually on disk.

Air-gapped installs, checksum verification and uninstall: Installation.

Regulation packs

Eight EU regulations, shipped as six adapter packs. gdpr is the default and the sensible one for almost any product repo.

--regulations value Covers
gdpr (default) General Data Protection Regulation
eu_ai_act Artificial Intelligence Act
eu_data_act Data Act
dora Digital Operational Resilience Act
dsa Digital Services Act
cra_dma_nis2 Cyber Resilience Act, Digital Markets Act and NIS2
precommiteu scan src/ --regulations gdpr,eu_ai_act

Each adapter is trained on code its own regulation governs, so scanning with all six is noisier rather than more thorough. Application dates, what each pack is for, and how several packs run in one scan are in Regulation packs.

Detection quality

precommitEU is not built to catch everything. The bar it aims for is: flag more than half of the real violations, and be right about nine out of ten things it flags.

From local evaluation runs on my own codebases, measured on confirmed findings (advisories are excluded):

Pack Precision Recall False positive rate
gdpr 97% 98% 6%
eu_ai_act 97% 93% 5%
eu_data_act 97% 93% 5%
cra_dma_nis2 97% 93% 5%
dsa 90% 90% 15%
dora 100% 73% 0%

Every pack clears both bars. dora is the most conservative and dsa the noisiest, but nothing here is a compliance guarantee - treat a clean scan as one useful signal, not as sign-off.

Numbers are for the shipped setup: shared base model plus the per-regulation LoRA adapter, loaded at runtime, exactly as a normal scan runs them.

In CI

- uses: actions/checkout@v4
  with:
    fetch-depth: 0
- uses: AlexandruGirlea/precommiteu@v0.1.0
  with:
    regulations: gdpr,eu_ai_act

--ci scans only the files changed against the merge-target branch. Exit code 1 on confirmed findings with --fail-on-findings, 0 when clean. GitLab, Azure DevOps, the full input list and every exit code are in CI integration.

Documentation

Guide Contents
Installation Requirements, per-platform install, model bundle download, CPU vs GPU, verify, uninstall
CLI reference CLI usage, complete flag reference, reports, suppressions
Regulation packs The six packs, application dates, choosing packs, multi-regulation runs
CI integration GitHub Actions, GitLab, exit codes, caching the model bundle
Python library Python API: scan_paths, scan_diff, schemas, callbacks
Report reference Report formats: JSON field reference, SARIF, summary, ledger
Ignoring and suppressing .eu-ignore, inline eu-ignore directives, audited precommiteu-ignore markers
Examples Worked scans, real output, common flag combinations
Troubleshooting Model paths, llama-server startup, empty scans, error messages

Rendered documentation site: https://alexandrugirlea.github.io/precommiteu/ Project site: https://precommit.eu

Disclaimer

precommitEU is free and fully open source under the Apache License 2.0, and is provided as is, without warranty or condition of any kind, express or implied, as set out in sections 7 and 8 of that license. Use is entirely at your own risk. There is no service level, no availability commitment and no guarantee of accuracy or fitness for any purpose.

It produces a compliance signal, not legal advice: it can report findings that are not violations and can miss violations that are present. Nothing it outputs establishes, certifies or evidences compliance with any regulation.

The author is not a lawyer and provides no legal, regulatory or compliance advice. This software does not replace legal analysis. To the maximum extent permitted by applicable law, Alexandru Girlea accepts no liability for any damages, losses, costs, regulatory outcome or misrepresentation arising from use of this software or reliance on its output. Have findings reviewed by qualified legal counsel before acting on them.

License

Apache License 2.0, see LICENSE, NOTICE and THIRD_PARTY_NOTICES.md. Copyright (c) 2026 Alexandru Girlea.

Everything precommitEU produces is Apache-2.0: the scanner, the per-regulation LoRA detector adapters, the GBNF grammars and the regulation knowledge packs, including everything in the model bundle. The base model weights (Qwen 2.5 Coder, Apache-2.0) and the llama-server binary (llama.cpp, MIT) are delivered separately and carry their own licenses.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

precommiteu-0.1.0.tar.gz (2.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

precommiteu-0.1.0-py3-none-any.whl (1.6 MB view details)

Uploaded Python 3

File details

Details for the file precommiteu-0.1.0.tar.gz.

File metadata

  • Download URL: precommiteu-0.1.0.tar.gz
  • Upload date:
  • Size: 2.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for precommiteu-0.1.0.tar.gz
Algorithm Hash digest
SHA256 06668fe077a8d2b69010762e91dfc46a304a02acddd11e36ff46381ef63420ea
MD5 199a91d9df80a58000f6d61930d9a5bd
BLAKE2b-256 77b7bf00f03533e87b18ac9bb6c255d41ec0ca3bdd5f7f839df8f1a0bea83331

See more details on using hashes here.

File details

Details for the file precommiteu-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: precommiteu-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for precommiteu-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 929070dcf003caddf486246e4b67a842d82521229c2c6752ca86811cb6c926d0
MD5 c6492910e1bed99101de4fa8d5c227f7
BLAKE2b-256 29f72a6d7629f160cd8a07d6004925255acdb2d64bc07339233866dadcaf167b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page