Compiled Build
Compile your app to a native binary with the license gate inserted automatically into every module — no plaintext Python ships, and there's no single check to find and delete.
The convenience tier ships readable-once-decrypted Python bytecode. magiclock build goes further: it auto-inserts a license-gate check into every module in your source tree, weaves that gate directly into compiled native code, encrypts any models you bundle, embeds your vendor's public key, and compiles the result — so there's no plaintext Python to read and no single check an attacker could find and patch out.
Nothing to mark
There's no decorator and nothing to annotate — you don't change your source at all. magiclock build app.py walks every .py module reachable from app.py, and inserts one gate check per module (checking the python_protect capability) before compiling. The entry module also gets a magiclock.air.bootstrap() call inserted automatically, so you don't need to add one yourself:
# your source, unchanged — no decorator, no bootstrap() call added by hand
def export_report(data: str) -> bytes:
return render_pdf(data)magiclock build app.py # every module in the tree — including this one — is gated automaticallyA gate check runs once per module, the first time Python imports it in a process — this is a per-module checkpoint, not a per-function-call one (see Security Model for what this means for long-running processes and expiry/revocation).
Build it
magiclock build app.py # -> dist/app.<...>.so (single compiled module)
magiclock build app.py --standalone # a self-contained app directory instead
magiclock build app.py --no-compile # scan + inject + embed only — skip compiling (no C toolchain needed)
magiclock build app.py --model weights.onnx # also encrypt a model into the build (repeatable)| Flag | Default | Meaning |
|---|---|---|
-o, --output-dir | dist | Where the build output is written. |
--source-root | the entry file | Project root to scan/transform (use this if app.py isn't at your project's top level). |
--module | — | Compile to a single-file native extension (the default target). |
--standalone | — | Compile to a self-contained app directory instead of a single module. Mutually exclusive with --module. |
--no-compile | off | Scan, inject the gate, and embed resources, but skip the actual native compile — useful for inspecting the transform, or on a machine without a C toolchain. |
--keep-tmp | off | Keep the intermediate transform directory instead of cleaning it up. |
--model PATH | none | Encrypt a model and bundle it into the build. Repeatable. |
--model-lock-passphrase | off | Add a passphrase as a second factor on bundled models (requires at least one --model). |
--model-trial / --model-expires-in / --model-expires-at | none | Expiry for bundled models — same semantics as Encrypting Code's expiry flags, mutually exclusive with each other. |
What ships
The compiled .so/.pyd/standalone directory needs no MagicLock install, no account, and no network on the machine that runs it — decryption and the license check are both fully offline (see Security Model).
By default, the compiled binary is node-locked: it only decrypts and runs on the machine that built it (the trust root is that machine's fingerprint). If you need the same build to run on more than one machine — a second workstation, a deployment server — activate that machine under your account too and build there; the compiled tier doesn't currently offer the portable (--no-bind-machine) unlock that Encrypting Code and Encrypting Models do.
What's next
- Security Model — why the compiled tier resists the "just find and patch the check" bypass that the convenience tier can't fully rule out.
- Account & Activation — activating additional build/deployment machines.