skip to content
all work
activeJuly 2026 – present

decide which Python plugins may run before importing them.

preflight

built with
  • Python
  • Rust
  • Pydantic
  • pytest
  • GitHub Actions
where it stands
the plugin gate is published and usable. artifact approvals are alpha; Windows isolation is not active.

Python imports are execution. Preflight puts a decision in front of them.

the problem it solves

A Python program that loads plugins has an awkward trust boundary: importing a module runs its top-level code. If the host imports a plugin to ask what it is or what tools it provides, the plugin has already run before the host can say no.

Preflight makes that decision from inert JSON on disk. Code that fails the gate never gets an import.

what it is

A manifest and a gate. The plugin author describes the package, entrypoint, tools, risk levels and release tier in manifest.json. The host supplies an explicit allowlist and the risks it will accept.

Nineteen checks. Fourteen run before any import happens. They validate the manifest, keep entrypoints inside the trusted plugin folder, enforce load order and policy, and refuse plugin or tool-name collisions. After import, Preflight verifies the module path, the plugin interface and the running plugin's self-description. A failed registration rolls back cleanly.

This is the engineering pattern I care about in agent and AI systems: make authority explicit, put one observable gate in front of execution, and fail closed when the gate cannot prove what it needs.

what it does not do

Preflight does not read source code, detect malware or decide that a plugin is safe. It enforces what a manifest declares. If an accepted plugin lies in code and then deletes files, opens a socket or spawns a process, the current plugin gate cannot stop it.

It is also not a pip gate, an MCP gateway or a working Windows sandbox. Those are adjacent problems, but claiming them now would erase the boundary the project is meant to make clear.

where it stands

The Python plugin gate is published on PyPI and usable today. The 0.8 artifact protocol is an alpha: it can hash local projects and Python archives, bind an approval to the exact artifact and command, revoke that approval, and write integrity-checked local evidence.

The Windows Blast Chambers work is earlier. Its Rust protocol, Job Object setup and fail-closed client foundation exist, but the native service is deliberately inactive. Secure transport, identity, staging, evidence-key custody, AppContainer isolation and the hostile acceptance suite are still work in progress.

That split is intentional and public: the narrow gate works; the larger trust and containment platform is not finished.

why this is the one to run

Everything else here is a system you would have to take my word for. This one is a pip install away:

pip install preflight-gate
preflight demo

That runs a deliberately broken set of plugins and prints which ones loaded, which were refused, why they were refused, and whether their code had already run. No private repo, prepared environment or access from me.

Here is that run, from an empty virtual environment on a machine that had never seen the package. Two absolute paths are shortened and their line wrapped; nothing else is changed:

  [greeter] top-level plugin code is executing
  [impostor] top-level plugin code is executing
  [janitor] top-level plugin code is executing

preflight | plugins\ | 5 packages found

  LOADED   greeter     Greeter 1.0.0 - 1 tool
  REFUSED  trespasser  never imported
                       entrypoint module 'json' resolves to '...\Python311\Lib\json\__init__.py',
                       which is outside the trusted plugin root '...\preflight\_examples\plugins'
  REFUSED  collider    never imported
                       tool name collision: 'greeter.hello' is already owned by 'greeter'
  REFUSED  impostor    imported, then rejected
                       runtime manifest for 'example.impostor' does not match its validated package manifest
                       tools -- undeclared in the manifest: impostor.purge_all_records
  LOADED   janitor     Janitor 1.0.0 - 1 tool

  2 loaded, 3 refused -- 2 of the 3 stopped before any of their code ran

The counts at the bottom are checkable rather than asserted. Every example plugin prints one line as the first statement in its package, and three of those lines appear above. Only impostor is refused after one — its manifest and its running code disagreed, which is not a thing you can know before importing it.

The demo closes by pointing at what it cannot do. Run it again with --refuse destructive and a fourth plugin is turned away for a tool it declared honestly, while impostor walks through the same flag, because it declared nothing.

what stands behind the release

Every merge runs the suite on three operating systems across four Python versions, plus lint, type checking, a dependency audit, a CodeQL scan on both languages, and a Rust workspace with warnings denied. One job takes all seven of those as dependencies and refuses the merge unless every one reports success. A job that was skipped or cancelled counts as a refusal too, so a check that never ran cannot pass for a check that passed.

Releases go out on a separate path. It builds twice under a fixed timestamp and compares the results byte for byte, publishes to TestPyPI, downloads that exact wheel back, compares it to the one it just built, installs it into a clean environment and runs it. Only then does it publish to PyPI, over trusted publishing, so there is no long-lived token to leak.

Windows is in the test matrix on purpose. The settings code reads the user config directory from %APPDATA% and compares paths with os.path.normcase. Neither branch runs anywhere else, and both decide whether a planted file counts as inside a folder being inspected.

Nobody else has committed here, so that gate has never refused someone else's merge. It has refused plenty of mine.

how I am building it

Preflight is AI-assisted. I use coding agents to implement, test and review, but I set the boundary, write the acceptance criteria and decide what the project may claim. That division is part of the work, not a disclaimer after it.

The project is how I am learning AI engineering from the systems side: harness design, tool admission, approval lifecycles, deterministic evidence, deployment gates and the uncomfortable work of proving that a security boundary is real. Leaving the unfinished parts visible is evidence of that judgment too.

contact

If the work overlaps with something you are building, message me.

opens in your email app

neil mahure

applied AI engineer · San Francisco Bay Area · neil@neilmahure.com

open to applied AI engineer and forward deployed engineer roles.