Skip to main content
Rebind code ships in two tiers, and one file decides which you’re in:
  • Script tier: a bare .lua/.luau file, no rebind.toml anywhere above it. The modeline comment at the top of the file owns all configuration.
  • Package tier: a directory (or any ancestor of the script) containing rebind.toml. The toml is package truth: it owns identity and can set every runtime option, overriding the entry’s modeline.
Promotion is additive: start with a single script, and when it outgrows one file, rebind init a package and move it in. Nothing about the code changes.

Layout

The entry defaults to main.luau, then main.lua. requires resolve inside the package root: <mod>.luau, <mod>.lua, <mod>/init.luau, <mod>/init.lua.

rebind.toml

[runtime] values are checked by the same rules as modeline values, so an unknown instance or a tick_rate above 8000 is an error, not a silent default. name, version, and min_sdk belong under [package] and are refused under [runtime]. The toml key is permissions (a list). In a modeline, permission= and permissions= behave identically: either takes one value or a comma-separated list, and every line adds to the set. An empty set means “declared, needs nothing”: permissions = [] in the toml, or permissions=none (or a bare permissions=) in a modeline. Omitting the key entirely is the opposite, and grants every permission. See Permissions. A package you intend to publish must declare the key. The registry refuses a version that leaves it undeclared, since “undeclared” reads as every permission, and rebind check fails it offline once [marketplace] is present. Declaring the empty set is always available for a script that needs nothing. Publishing adds a third section, [marketplace]. It is only read by rebind check and rebind publish, never by the runtime: see the marketplace listing.

Precedence: toml over modeline

Inside a package, the entry’s modeline still works (an entry can run standalone during development), but any key also set in rebind.toml wins, and the collision is surfaced as a warning on the script’s log channel. A bare script outside any package declares min_sdk in its modeline.

Scripts inside a package

Any script under a package root (for example scripts/wiggle.luau) runs in that package’s context, with deliberate limits: So a one-shot helper needs zero boilerplate:
exit() (alias for Script.Exit()) ends the script cleanly when it’s done.

Importing from GitHub

A package in a public GitHub repository installs from the app. In the Scripts tab, open More file actions above the file list and choose Import from a link, then paste the repository link. The rebind.toml must sit at the top of the repository. A /tree/<ref> link takes a branch or a tag, and the ref may contain slashes. Packages inside a folder are not supported.
The import dialog over the script editor, with a link field and Cancel and Check buttons

Import from a link: paste a public repository link, then Check before anything installs.

Check shows what GitHub says about the repository: description, stars, last push, the size of the whole repository with its history, and whether a rebind.toml exists. Nothing is downloaded yet. Download and check fetches it and shows the package name, version, file count, commit, and requested permissions before anything is written. Import installs that exact commit under repos/<repo> in your scripts folder. Rebind has not reviewed this code, so import only from authors you trust. To pull a newer commit later, right-click the folder, choose Fetch update, and confirm with Replace. Local edits in that folder are replaced too. A folder imported by an earlier version still fetches updates.

A single script from a gist or a paste

The same dialog takes a gist.github.com or pastebin.com link to one standalone script. The gist must hold exactly one .luau or .lua file. The script must declare -- rebind: name= and compile, otherwise it is not importable. Check fetches the whole file and shows its name, version, size, and requested permissions. Import fetches it again, refuses it if it changed since the check, and writes it under imports/ in your scripts folder. There is no Fetch update for these: import the link again to replace the file.

Add an import button to your README

GitHub removes rebind:// links from a README, so the button points at a rebind.gg page that hands the link to the desktop app. Replace OWNER/REPO:
The url can also be a gist or a paste link. The button only opens the import dialog with the link filled in. Nothing is fetched or installed until the user presses Check, then Import. Every link brings Rebind to the front. None of them installs, sends, or buys anything on its own.

The .rbp artifact

rebind pack produces the registry artifact: a gzipped tarball of the package’s source, rebind.toml, and README.md, with hidden files and folders (names starting with a dot), build output, and any .rbp excluded. Listing media under assets/ is uploaded separately at publish and is not packed. A DRM listing ships no archive at all: see DRM packages. For validation and repacking after extraction, see Installed and extracted packages.

The marketplace listing

[marketplace] is publish-time configuration. A package without it is a valid dev package; rebind publish refuses without it. rebind init scaffolds the block commented out. Unknown keys inside [marketplace] or [marketplace.price] are errors.
Prices are USD with at most two decimals. Subscription prices are locked in at subscribe time: an approved price change applies to new subscribers only. Existing subscribers keep their price until they cancel. rebind check validates the shape and caps of whatever the block declares, offline, against the limits below. Presence is rebind publish’s job: it refuses a listing without a summary or without at least one PNG image in media. rebind preview renders the listing as a local HTML page before anything is uploaded. The server re-validates everything at publish.

Categories

Category is what the script does for the buyer. File a game, streaming, or accessibility tool under that domain first; file everything else by mechanism. Tags carry the other axis: a rapid-fire script filed under gaming can carry tags = ["macro"].

Listing media

Both icon and media are file paths inside the package, under assets/. You never supply a URL; publish uploads the files and the marketplace stores its own keys. Media is not packed into the .rbp. The first PNG image in media becomes the cover used by the grid and product page. Publish removes it from the remaining gallery so it does not appear twice. At least one PNG image is required, even when icon is set. The optional icon is a separate listing asset and never becomes a gallery slide. Remaining media entries keep their declaration order. A cover can illustrate the package’s behavior or show a screenshot. Label generated illustrations clearly; they are not evidence of runtime behavior. Screenshots and demo video must come from the running script or its real UI. Keep editable artwork source outside the packed package directory and declare the exported listing images under assets/.

README.md

A README.md at the package root is the listing’s long description. It ships inside the .rbp as well, so an installed copy reads offline.
  • Rendered as markdown in the product page overview card.
  • Packages only. A bare script never picks one up.
  • Without one, the product page falls back to summary.

DRM packages

drm = true needs a price and changes how the package ships. rebind publish resolves the require graph and bundles every module into one file, so the buyer receives a single sealed script instead of a directory of source. No .rbp is uploaded for a DRM listing. The sealed file opens with the merged [package] and [runtime] declarations written as modelines, so the buyer’s relay applies the same permissions and targeting the manifest declared. Two things cannot survive the flattening, and rebind check refuses them once drm is set:
  • require() with a non-literal argument. A sealed file resolves its modules before it runs, so every module name must be a string literal.
  • Data files a module reads at runtime (File.Read, Config.ReadTOML, Audio.Play). They would not reach the buyer. Inline the data into a .luau module, or publish without DRM.
Paid is independent of DRM. Entitlement gates on price, so a paid package with drm = false is still gated at download and arrives as plaintext. A sealed script runs only with an activated Rebind Link.

Limits

The one home for every cap. rebind check enforces the ones it can see offline; the server enforces all of them at publish.