Skip to main content

Luafend

Command line tool and Python library for Luafend — source protection for Lua and Luau. One package: protect a script from your terminal, from a build script, from CI, or from your own Python code.

Targets Luau, Lua 5.1 and Lua 5.4, covering Roblox, Garry's Mod, LuaJIT, embedded Lua and standalone hosts.

Install

pip install luafend

Or without installing it into your project:

pipx install luafend

Requires Python 3.9 or newer. Standard library only, no dependencies.

Two ways to run the command line

Type one word — in Command Prompt or PowerShell on Windows, in Terminal on macOS and Linux — and Luafend opens its own shell. Inside it, every command starts with a slash:

luafend

luafend ~ > /login
luafend ~ > /obfuscate main.lua --mode maximum
luafend ~ > /exit

Tab completes commands, files, flags and values. Typing -- suggests the flags that command accepts. /help lists everything.

Or drop the slash and run the same command straight from your own shell. Nothing opens, the job runs, you get your prompt back — this is the form a build script or CI job uses:

luafend login
luafend obfuscate main.lua --mode maximum --lua luau

Getting started

luafend login                    # opens your browser, no password typed
luafend obfuscate main.lua       # writes main.obf.lua

The first run asks for the mode and the Lua version and remembers both. Every run after that is silent, and prints what it used and where the setting came from.

Use it from Python

If you protect more than one script, write the key once:

import luafend

client = luafend.Luafend(key="luf_YOUR_KEY")
client.mode = "maximum"

result = client.run('print("hello")')

if result.ok:
    print(result.output)
else:
    print(result.error)

Or describe a single build one line at a time:

import luafend

job = luafend.Job()
job.key = "luf_YOUR_KEY"
job.source = 'print("hello")'
job.mode = "maximum"
job.lua = "luau"

result = job.run()

if result.ok:
    print(result.output)
else:
    print(result.error)

run() never raises. Every Result also carries the measurements, with no flag to switch on:

print(result.size, "bytes")        # protected script
print(result.source_size, "bytes") # what you sent
print(result.seconds)              # how long it took
print(result.timestamp)            # when it finished, UTC
print(result.quota_left)           # obfuscations left this month

Set job.out = "main.obf.lua" and the file is written for you as UTF-8, line endings intact.

If you just want the string and are happy for a failure to stop the program, there is a one line form that raises luafend.LuafendError instead:

print(luafend.obfuscate('print("hello")', key="luf_YOUR_KEY", mode="maximum", lua="luau"))

Leave key out and LUAFEND_TOKEN is used, then the account from luafend login. mode is lite, balanced or maximum; lua is luau, lua-5.1 or lua-5.4.

Commands

Command What it does
login Sign in through your browser
logout Sign out and revoke this machine's token
whoami Name, email, sign-in provider, plan
billing Plan, credits, monthly usage and limits
obfuscate <file> Protect one script
batch <pattern> Protect many files at once
settings Show, reset or write project settings
cd [folder] Show or change the current folder
update Check for a newer version and install it
docs Open the documentation
version Show the CLI version

Options

Flag Meaning
--mode lite|balanced|maximum How much protection. Lite is fastest, Maximum compiles the script into its own virtual machine
--lua luau|lua-5.1|lua-5.4 Which Lua the result has to run on
-o, --out <path> Where to write. A folder for batch, a file for obfuscate
--pick Choose mode and version again instead of using the saved ones
--force Overwrite an existing output file
--stdout Print the result instead of writing a file
--all batch only: rebuild every file, including unchanged ones

Without --lua, the version is guessed from the file: a .luau extension or Roblox globals such as game:GetService mean Luau. The guess is always printed.

Protecting many files

luafend batch "src/**/*.lua" -o dist

* and ? never cross a path separator, ** matches any number of directories. A plain folder means every .lua and .luau inside it. Files that have not changed since their last build are skipped, so a rebuild does not spend your monthly quota twice. Requests are paced to your account's rate limit.

Project settings

luafend.json pins how a project builds, so everyone working on it gets the same result:

{
  "mode": "maximum",
  "lua": "luau",
  "out": "dist",
  "include": ["src/**/*.lua"]
}

It is searched for upwards from the current folder, so any subfolder of the project behaves the same. With an include list, plain luafend batch is enough.

luafend settings shows what applies and where each value came from. luafend settings init writes a starter file next to your token, which then applies everywhere you have no project file.

Signing in

login never asks for a password. It opens a consent page in the browser where you are already signed in and waits for approval. The token it receives is stored in your OS config directory, never in the working directory:

Windows %APPDATA%\luafend\config.json
macOS ~/Library/Application Support/luafend/config.json
Linux ~/.config/luafend/config.json

On macOS and Linux the file is created with mode 0600. logout revokes the token on the server as well as deleting it here.

The token is only ever sent to the official Luafend API or to a server on your own machine.

In CI

Set LUAFEND_TOKEN instead of signing in. It takes priority over the config file, so no login step is needed:

- run: pip install luafend
- run: luafend batch "src/**/*.lua" -o dist --mode balanced --lua luau
  env:
    LUAFEND_TOKEN: ${{ secrets.LUAFEND_TOKEN }}

Without a terminal, nothing is ever asked interactively: a missing setting fails with the flag it needs named, rather than blocking on a prompt nobody can answer.

Exit codes:

Code Meaning
0 Success
1 Error
2 Not signed in, or the session expired
3 Out of credits, or the plan does not allow that mode

Environment

Variable Effect
LUAFEND_TOKEN Use this token instead of the stored one
LUAFEND_API Point at a different API host, for local development
NO_COLOR Turn colour off
LUAFEND_ASCII=1 Plain ASCII instead of box drawing characters

Links

Release files for luafend 2.3.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 luafend 2.3.0
File Size Uploaded
luafend-2.3.0.tar.gz 32.0 kB Details

Built distribution (wheel)

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

Total release size: 64.7 kB

Release files / luafend-2.3.0.tar.gz

Download URL luafend-2.3.0.tar.gz
Size 32.0 kB
Tags Source
SHA-256 checksum
How to use checksums
b3b73071225af347dbd308270d2b974ccb5ab6b0ce254b799d1b35cd6f37a999
BLAKE2b-256 checksum
How to use checksums
d7338b50acf0ef28a78fdcc89720792a88876415fce3c312b50fa1192ef062e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.0

Release files / luafend-2.3.0-py3-none-any.whl

Download URL luafend-2.3.0-py3-none-any.whl
Size 32.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
06cebd4771f003c7f2b8eaa7e3723536cb82c3ddc37673018f6e4e020c5080b2
BLAKE2b-256 checksum
How to use checksums
50b36747a776d964f5b51d2630a59ea1eb980f7eb1ece97d639f4b6a66afeb18
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.0

Release history Release notifications | RSS feed

2.5.0

2 release files

2.4.0

2 release files

This release

2.3.0 This release

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