Skip to content

SinisterClient Lua Bridge (lua_bridge_sinclient.lua)

Optional in-game helper for custom scripts. It talks to the SinisterClient desktop app over 127.0.0.1 — not to the Sinister backend directly from Roblox.

This is separate from Sinister Script (the licensed /get-script product). Subscribers who use Sinister Script normally do not need this file.


Download URL

Served from your Sinister host — the same domain as Sinister Script, /get-script download links, and /script/boot.lua:

EndpointPurpose
/script/lua_bridge_sinclient.luaModule (returns luaBridge namespace; luaBridge.HOST is set by the server)
/script/lua_bridge_sinclient.run.luaDrop-in loader — connects and triggers one resolve (host baked in by the server)

Replace YOUR_SINISTER_HOST below with that domain (no path, no trailing slash). Example: app.sinistersoftworks.xyz.


Requirements

  1. SinisterClient running and signed in (starts the local bridge automatically).
  2. Roblox launched after SinisterClient so the proxy can capture joins.
  3. An executor with a request function that can reach 127.0.0.1 (plain HttpService cannot).

How luaBridge.resolve() works

luaBridge.resolve() does not choose what gets resolved. SinisterClient does.

When you join Roblox through SinisterClient’s proxy, the desktop app captures a pending intercept (job ID, username, reserved access code, etc.) — the same data shown in the client UI before you press Resolve. Calling luaBridge.resolve() from in-game only triggers that pending resolve on the desktop app. It is equivalent to clicking Resolve in SinisterClient.

You pass to resolve()Used for
(nothing)Trigger resolve using the client’s pending intercept and current UI slider values
{ power?, duration?, chains? }Same trigger, but temporarily override power / duration / chain count for this one call

You do not pass place ID, universe ID, or job ID. SinisterClient already has the resolve target from the intercept it captured at join time.

The module does send place_id and universe_id in the localhost POST body, but those are filled automatically from game.PlaceId and game.GameId. They are not the resolve target and not part of the public API. They exist only for bridge security and logging:

  • Universe lock — limit bridge use to the game you joined through the client
  • Rate limits — throttle resolve calls per place
  • Telemetry — record bridge usage on the backend

If resolve does nothing, the problem is almost always no pending intercept — re-join through SinisterClient’s proxy, not missing place/universe arguments.


Quick start (loadstring)

The server injects your Sinister host into the module and into .run.lua. Use the same host as your /get-script or client download page.

Drop-in resolve (simplest):

lua
loadstring(game:HttpGet("https://YOUR_SINISTER_HOST/script/lua_bridge_sinclient.run.lua", true))()

Load the module manually:

lua
local luaBridge = loadstring(game:HttpGet(
    "https://YOUR_SINISTER_HOST/script/lua_bridge_sinclient.lua", true))()

if luaBridge.init() then
    luaBridge.resolve()
    -- optional overrides for this resolve only:
    -- luaBridge.resolve({ power = 10, duration = 20, chains = 2 })
else
    warn("SinisterClient not detected on localhost.")
end

The optional table only overrides SinisterClient slider values for that call (power 1–15, duration 5–30, chains/chain 1–10). See How luaBridge.resolve() works above — you never pass place or universe IDs.

After load, call functions on the namespace with dot syntax — luaBridge.init(), luaBridge.resolve(), etc. No :new() and no global LuaBridge table that could clash with host scripts.

Assign to a local if you want to avoid overwriting a host luaBridge name:

lua
local sinBridge = loadstring(game:HttpGet(
    "https://YOUR_SINISTER_HOST/script/lua_bridge_sinclient.lua", true))()
sinBridge.init()

Use luaBridge.moduleUrl() for the module path on your configured host.

More patterns: Examples.


Auto-execute

Not required. Only add to your executor’s auto-exec folder if you want this to run on every join.

lua
pcall(function()
    loadstring(game:HttpGet(
        "https://YOUR_SINISTER_HOST/script/lua_bridge_sinclient.run.lua", true))()
end)

Use the same host as your /get-script link — there is no separate bridge URL setting.


Trust-gated schedule reporting

Bridge feedback (worked / partial / failed) is protected against griefing:

  1. Your plan must include Lua bridge access (access_lua_bridge).
  2. Bridge reporting trust must be enabled on your account by support (Access Hub or an admin action).
  3. Until trusted, feedback is saved locally on your PC (~/.sinister_lua_bridge_states/user_<id>.json) and does not hit the live schedule API.
lua
luaBridge.reportWorked()
luaBridge.reportPartial()
luaBridge.reportFailed()
-- { ok = true, status = "recorded" } when trusted
-- { ok = true, status = "queued_local", message = "..." } when not trusted yet

Check status:

lua
local status = luaBridge.fetchBridgeStatus()
-- status.access.lua_bridge_report_trusted
-- status.local_queue_size

API

MethodDescription
luaBridge.HOSTSinister server base URL (from your deployment)
luaBridge.moduleUrl()Full URL to this module on your server
luaBridge.isConnected()Whether init() found SinisterClient on localhost
luaBridge.init()Scan ports 4771147721 for SinisterClient
luaBridge.fetchToken()Get the active JWT from SinisterClient
luaBridge.resolve(options?)Trigger only — runs SinisterClient resolve on its pending intercept. Optional { power?, duration?, chains? } overrides desktop sliders. Does not accept place ID, universe ID, or job ID
luaBridge.fetchIntercept()Read sanitized intercept data without resolving
luaBridge.fetchBridgeStatus()Addon, trust, and local queue info
luaBridge.reportWorked(placeId?, jobId?, ip?)Feedback: join worked
luaBridge.reportPartial(placeId?, jobId?, ip?)Feedback: partially worked
luaBridge.reportFailed(placeId?, jobId?, ip?)Feedback: did not work
luaBridge.reportSuccess(...) / reportFeedback(...)Lower-level feedback helpers

Reserved servers

  1. Open SinisterClient and sign in.
  2. Launch Roblox through the client proxy.
  3. Attempt to join the reserved server in Roblox (client captures place ID + access code).
  4. Run luaBridge.resolve() — SinisterClient resolves using the intercept it already captured (not place/universe IDs from your script).

To read intercept data without resolving:

lua
if luaBridge.init() then
    local intercept = luaBridge.fetchIntercept()
    if intercept and intercept.resolve_type == "reserved" then
        print(intercept.placeid, intercept.accesscode)
    end
end

For a full in-game UI and backend resolves, use Sinister Script (/get-script) instead.


Obfuscation

Plain Lua — not obfuscated or per-user licensed. Security relies on SinisterClient being signed in on the same machine.


Localhost endpoints (SinisterClient)

EndpointMethodPurpose
/healthGETDetect client
/tokenGETSession JWT
/interceptGETPending intercept (Bearer token)
/resolvePOSTTrigger desktop resolve on pending intercept. Optional body: power, duration, chains (or chain). place_id / universe_id are sent automatically by the module from the current game for rate limits and universe lock — not the resolve target
/report-successPOSTJoin feedback
/bridge-statusGETPlan access, trust, local queue size

Default port: 47711 (falls back up to 47721).


Troubleshooting

ProblemFix
init() returns falseSinisterClient not running or not signed in
Resolve does nothingNo intercept captured — re-join through the client proxy
401 on /resolveRe-sign-in to SinisterClient
Wrong host in moduleHost mismatch — use the same domain as your download links; contact support if the URL looks wrong
Executor blocks localhostUse an executor that allows 127.0.0.1 requests

Sinister Script vs this bridge

Sinister Scriptlua_bridge_sinclient.lua
Get it/get-script/script/lua_bridge_sinclient.lua on your Sinister host
ObfuscatedYes (per user)No
Backend APIYesNo (localhost only)
UIFull in-game UINone (library only)
Best forSubscribersCustom script authors

See also: Sinister Script overview · SinisterClient overview