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  ·  Local UI  ·  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

Local UI

New in 0.2. A local web UI ships with the package. Point it at a folder and watch the run: readiness checks, the plan, per-file progress and ETA, then confirmed findings and advisories. It drives the same scanner as a subprocess and writes nothing into the folder being scanned.

Findings from a local EU AI Act scan in the precommitEU UI

pip install "precommiteu[ui]"
precommiteu ui

That serves http://127.0.0.1:8787 and nothing else. You pick what to scan from the Target screen: a folder on this machine, or a repository URL it clones for you. The scanner never touches anything until you do.

Nothing else to install by hand either. The readiness screen installs what is missing where it can, and the regulation screen downloads adapter packs on demand, verifying each against the bundle checksums. One pack is active at a time; picking another switches it.

The Target screen knows what was already analysed: scan only the changed files, start clean and rescan everything, or forget the cached findings for that folder. The Settings screen shows where this machine keeps the model bundle, the scan cache and the reports, and moves any of the three without a restart. Available in English, Romanian, German, French and Italian.

Every screen, the download flow, pause versus stop, and what the UI sends over the network: Local UI.

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.
  • Only what changed. Every file that completes cleanly is recorded, and the next scan of the same folder replays it instead of analysing it again, so a repository that took hours the first time takes minutes when a handful of files moved. The record is one small JSON file per folder and regulation under ~/.precommiteu/scans/; nothing is written into the folder you scan. --rescan-all forces a full pass. Reuse rules, change detection and CI behaviour: Incremental rescans.

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.2.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
Local UI The six steps, downloading packs, pause vs stop, settings, what leaves the machine
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.

Metadata

Release files for precommiteu 0.2.0

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

Source distribution (sdist)

Source distribution for precommiteu 0.2.0
File Size Uploaded
precommiteu-0.2.0.tar.gz 3.3 MB Details

Built distribution (wheel)

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

Total release size: 4.9 MB

Release files / precommiteu-0.2.0.tar.gz

Download URL precommiteu-0.2.0.tar.gz
Size 3.3 MB
Tags Source
SHA-256 checksum
How to use checksums
23fe8f9cc1c0738ce49d46c686357518139cd5421b3923f9df85b286bb58f55a
BLAKE2b-256 checksum
How to use checksums
52259ae34691c73f2cfcc0c5efe1719b4883e8640cd387ff1c675838cc3b56fa
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release files / precommiteu-0.2.0-py3-none-any.whl

Download URL precommiteu-0.2.0-py3-none-any.whl
Size 1.6 MB
Tags Python 3
SHA-256 checksum
How to use checksums
9c8dd2e0a78c265c6c6427da9a91978b979ed7572982a9fbc02c0393732c6404
BLAKE2b-256 checksum
How to use checksums
35883bd73d8f1ccb3bad0ff226371f4cbc976b569cda01868feccf104d37a819
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release history Release notifications | RSS feed

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

This release

0.2.0 This release

2 release files

0.1.0

2 release files

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