> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rebind.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# Modeline

> The header that names a script, sets its target, and declares its permissions.

A modeline at the top of a script sets its configuration. A directly-run script
must declare `min_sdk`, in its modeline or in its package's `rebind.toml`. For a
package's entry, `rebind.toml` wins; another script in the package keeps its own
modeline values (see
[Package format](https://docs.rebind.gg/reference/packages.md#precedence-toml-over-modeline)). A
`require`d module needs none.

This script is active only while Notepad is focused and its window title does
not contain `Untitled`. It needs no permissions, refuses a second start while it
runs, and prints a line each time it becomes active or inactive:

```luau theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
-- rebind: min_sdk=3.9.0 name=example version=1.0.0
-- rebind: process=notepad.exe exclude_window=Untitled
-- rebind: permissions=none instance=single

rb.on("focus", function()
  print("active")
end)

rb.on("blur", function()
  print("inactive")
end)
```

A modeline can use three comment forms. This script uses the block form and the
single-line form:

```luau theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
--[[
  rebind: min_sdk=3.9.0
  rebind: name=My Script
  rebind: version=1.0.0
  rebind: process=chrome.exe process=firefox.exe
]]
-- rebind: tick_rate=500

rb.on("tick", function(dt_ms) end)
```

The block form takes one `rebind:` line per setting. The single-line form is
`-- rebind: key=value key=value`, and the third form, the inline block, is
`--[[ rebind: ... ]]`. Values end at the next space unless quoted with `"` or
`'`; inside quotes, escape the quote and backslash as `\"` and `\\`. A string key (`name`,
`description`, `author`, and the targeting keys) alone on its line takes the rest
of the line, so `rebind: name=My Script` needs no quotes. Repeatable keys may
repeat on one line or across lines. An unknown key is ignored, with a warning in
the script's log and in `rebind check`.

| Key | Type | Default | Meaning |
| - | - | - | - |
| `min_sdk` | version | required | the oldest Rebind the script runs on. Numeric; `3` means `3.0.0`, a leading `v` and suffixes are ignored. Rebind refuses a script without it, or one asking for a newer version than it is. `rb` needs `3.9.0` |
| `name` | string | `Untitled` | display name |
| `version` | string | `0.0.0` | the script's version |
| `author` | string | none | |
| `description` | string | none | |
| `window` | string | none | active while the focused window's title contains it; repeatable, any case |
| `process` | string | none | active while the focused process name contains it; repeatable, any case |
| `window_regex` | regex | none | title regular expression; repeatable, any case |
| `process_regex` | regex | none | process name regular expression; repeatable, any case |
| `exclude_window` | string | none | inactive while the title contains it; repeatable |
| `exclude_process` | string | none | inactive while the process name contains it; repeatable |
| `exclude_window_regex` | regex | none | repeatable |
| `exclude_process_regex` | regex | none | repeatable |
| `tick_rate` | integer | 1000 | `tick` events per second, 1 to 8,000 |
| `z_index` | integer | 1 | input order between scripts; higher sees input first |
| `instance` | string | `replace` | what a second start of the same file or source does: `replace` stops the running copy first, `single` refuses with `script '<name>' is already running (<id>)`, `multiple` runs both |
| `key_block` | boolean | `true` | `false`: a `down` or `up` handler observes keys without exclusive capture, and its `false` cannot block them. Binds are unaffected |
| `mouse_block` | boolean | `false` | `true`: a `move` handler can block movement. Hardware mode only |
| `hardware_only` | boolean | `false` | Rebind refuses to load the script outside hardware mode; a startup script waits for it |
| `macro` | boolean | `false` | marks a [macro file](https://docs.rebind.gg/reference/sdk/macro.md#macro-files) |
| `platforms` | list | all | `windows`, `macos`, comma separated; Rebind refuses to load the script elsewhere |
| `memory_limit_mb` | integer | 8 | Luau heap limit in MB |
| `permission` | list | none | see [Permissions](#permissions); `permissions` is the same key |
| `permission_reason` | string | none | `"<family>: <reason>"`, repeatable; see [Reasons and approval](#reasons-and-approval); `permission_reasons` is the same key |
| `mouse_mode` | string | `relative` | deprecated: `relative` or `absolute`, no effect |

Booleans accept `true`, `false`, `1`, `0`, `yes`, `no`. `include_window` and
`include_process` are older spellings of `window` and `process`, and `platform`
of `platforms`. The `id` key is ignored with a warning.

Positive targeting rules combine with OR. With none, the script is active in
every window. A matching exclusion deactivates it even when a positive rule
matches. Regular expressions use Rust `regex` syntax; an invalid or empty one
stops the script from loading. A script with regex or exclusion targeting
should declare `min_sdk=3.4.1` or later, so that a Rebind without these keys
refuses the script instead of ignoring its scope.

## Permissions

A script with no `permission=` line holds every permission except `observe`.
Once any line is present, only the listed permissions are granted:
`permission=net` alone also denies `exec`. `permission=` and `permission=none` declare that the script needs
nothing. Each non-empty line adds to the set, and a comma list adds several;
an empty value or `none` resets the set to empty. In a package,
`permissions = []` in `rebind.toml` means the same.

| Permission | Gates |
| - | - |
| `exec` | `rb.system.exec`, `rb.system.exec_detached`, `rb.env.set`, `rb.pipe.open`, and `loadstring` |
| `net` | all of `rb.net` |
| `screen` | pixel reads (`rb.screen.pixel_hex`, `search_color`, `capture`, `find_image`) and `rb.ai` looks, anywhere on the screen |
| `ai` | `rb.ai.decide`, `rb.ai.find`, `rb.ai.read`; `min_sdk` 3.10.0 |
| `observe` | all of `rb.observe`, held only when listed; `min_sdk` 3.15.0 |

The clipboard has no plain name: a list reaches it through the
[`clipboard:read` and `clipboard:write`](#scoped-permissions) entries.

`loadstring` exists only for a script whose list includes `exec`, or one with no
permission line and a `min_sdk` below 3.9.0. Any other plain name grants nothing
but still switches the script to a list. A denied call raises when it runs, for
example `Net.Get() requires 'net' permission. Add -- rebind: permission=net to
your script.`, so a call in an untaken branch
never fails. Once a call is refused, Rebind stops the script, even when the
script catches the error with `pcall`, and shows a notice naming what it was not
allowed to do. `rb.file`, `rb.registry`, `rb.process`, `rb.env` apart from
`rb.env.set`, `rb.input`, `rb.hid` and `rb.macro` have no permission check;
`rb.file` paths stay inside the script directory and its data folder regardless. Ending programs
needs no permission (`rb.process.kill`, `rb.app.quit`, `rb.window.kill`), and a
value written under a Windows Run key with `rb.registry` starts a program at the
next sign-in.

### Reasons and approval

The install screen lists what a script can do and shows the author's reason
beside each sensitive item. A marketplace package must give a reason for `exec`,
for `net` or any `net:` entry, for `screen` or `screen:target`, and for
`observe`: `permission_reason="net: Posts your scores"` in a modeline, or
`permission_reasons = ["net: Posts your scores"]` under `[runtime]`.
`rebind check` refuses a package with a `[marketplace]` block that leaves one
out.

A script installed from the marketplace or a share loads only while its
permissions and targets stay within what you approved. An update or edit that
asks for more, or targets something else, waits for your approval. `net` covers
every `net:` entry, `ai` every `ai:` entry, and `screen` covers
`screen:target`. Nothing else covers `observe`.

### Scoped permissions

**Needs:** `min_sdk=3.8.0`.

A `family:scope` entry grants one part of a kind of access. Rebind refuses to
load a script with a scoped entry and an older `min_sdk`, an unknown family, or
a malformed scope.

| Entry | Allows |
| - | - |
| `net:example.com` | the HTTP client calls and `ws_connect` to `example.com` only |
| `net:*.example.com` | the same calls to subdomains of `example.com`, not `example.com` itself |
| `net:127.0.0.1`, `net:[::1]` | an IP address, written exactly; wildcards never match an IP |
| `clipboard:read` | `rb.clipboard.get` |
| `clipboard:write` | `rb.clipboard.set` |
| `clipboard:none` | neither; the same as listing no `clipboard:` entry |
| `screen:target` | pixel reads and `rb.ai` looks only while the script's target window is focused, and only inside it |
| `screen:none` | no pixel reads or `rb.ai` looks; the same as listing no screen entry |
| `ai:decide`, `ai:find`, `ai:read` | that `rb.ai` call |

Rules:

* **Network.** Ports and schemes are not matched, so `net:127.0.0.1` reaches
  every local port. A script limited to `net:` entries follows no HTTP redirects
  (it gets the `3xx` response) and cannot set a `Host` header. `rb.net.listen`,
  `ws_listen`, `udp_listen` and `local_ip` still need bare `net`. Listing `net`
  with `net:` entries is refused. A call to a host the list does not name raises,
  for example `Net.Get() to '<host>' is blocked: permissions do not list
  net:<host>`.
* **Clipboard and screen.** A script that declares permissions reaches the
  clipboard only through its `clipboard:` entries and the screen only through
  `screen` or `screen:target`, so `permissions = []` allows neither. Listing
  `screen` with a `screen:` entry is refused. A `none` entry cannot be combined
  with another entry of its family, and a script lists at most one `screen:`
  entry.
* `screen:target` needs a positive `window`, `process`, `window_regex` or
  `process_regex` rule. A read outside the window, or while another window is
  focused, raises. `rb.screen.list` and `rb.screen.work_area` stay open.

Scoped entries describe what a script asks for; they do not make an untrusted
script safe. `exec` and typing through `rb.hid` can reach the network without a
`net` entry, and hosts are matched by name, not by the address they resolve to.

```toml theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
[runtime]
process = ["PathOfExile.exe"]
permissions = ["net:poe.ninja", "net:*.poe.ninja", "clipboard:read", "screen:target"]
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.