1One file, one macro
This is a complete script. Save it as dev-keys.luau, set REPO to one of your repositories, and start it with rebind run dev-keys.luau.
-- rebind: min_sdk=3.9.0 name=dev-keys version=1.0.0 permissions=exec
local REPO = (rb.env.home() or "") .. "/code/my-repo" -- your repository
-- Right Alt (Right Option on a Mac) becomes Escape
rb.bind.remap("RAlt", "Escape")
-- F5 logs git status for REPO without leaving the editor
rb.bind("F5", function()
rb.run(function()
local result = rb.system.exec("git status --short", { cwd = REPO, timeout = 10000 })
if result.exit ~= 0 then
rb.log.error(result.stderr)
else
rb.log.info(result.stdout)
end
end)
end)
The first line is the modeline: the script's name, its version, the oldest Rebind it runs on, and its permissions. It asks for exec and nothing else, so a network call from this script would be refused.
rb.bind.remap holds Escape for as long as Right Alt is down. rb.bind takes F5 and leaves every other key alone, and rb.run starts a coroutine so the command runs on a worker thread instead of holding up your input.
2The loop in four steps
Install Rebind
Download Rebind, free on Windows and macOS. The standard install puts the
rebindcommand on your path.Give your editor the types
In VS Code, add the Luau Language Server and point it at Rebind's definition file. Every
rbcall gets autocomplete, hover docs, and type checking.Run it while you edit
rebind runchecks the script, loads it, and prints its log lines. Save a change and it checks and reloads. A failing check keeps the last good version running.Poke at it
rebind exec 'return rb.input.is_down("Shift")'runs one line inside Rebind.rebind logsstreams every script's output, andrebind lintflags definite bugs such as a misspelled global.
Free on Windows and macOS. Your macros stay plain text.
Download Rebind free3What a script can reach
| Job | Call | Note |
|---|---|---|
| Remap a key or chord | rb.bind.remap("Mouse4", "LCtrl+V") | Holds the target while the key is held |
| Run code on a hotkey | rb.bind("LCtrl+M", fn) | Only the keys you bind are intercepted |
| Per-app layers | process= in the modeline | Active only while that app has focus |
| Shell commands | rb.system.exec | Needs exec; cmd.exe on Windows, sh on macOS |
| HTTP, WebSocket, UDP | rb.net | Needs net |
| Files and JSON | rb.file, rb.json | Paths stay inside the script folder |
| Timers | rb.timer.every, rb.sleep | rb.sleep works inside rb.run |
All of these work the same on Windows and macOS. Screen, window, and app calls differ by platform; the SDK reference lists every call.
4What it won't do
- Change mouse movement without hardware. The free app remaps keys and buttons. Holding back or reshaping mouse movement needs hardware mode and a Rebind Link or BYOH.
- Tell two keyboards apart without hardware. Per-device binds and game controllers need hardware mode too.
- Stand in for
rebind check. The language server checks types.rebind checkalso validates the modeline, the permissions, and everyrequire.
5Other ways to script input
- AutoHotkey. Free, Windows only, its own language.
- Karabiner-Elements. Free, macOS only, rules written as JSON.
- Keyboard firmware such as QMK. Runs on the board itself, only on boards that support it, and changing its logic is a reflash.
- Rebind. Free, Windows and macOS, Luau with a typed SDK and a CLI.
6Questions
Do I need any hardware?
No. Key and button scripts run on the free app with the keyboard and mouse you have. Scripts that change mouse movement or read a controller need a Rebind Link or BYOH.
Can my scripts live in git?
Yes. A script is a text file, and a package is a folder with a rebind.toml. rebind init scaffolds one with a .gitignore.
Does it cost anything?
No. Rebind is free, and writing and running your own scripts needs no subscription.
Your next macro is a text file
Install Rebind, save a .luau file, and run it with rebind run.