Find out exactly why your Roblox game broke.
Workshell puts every error, log, trace and exploit flag on the timeline of the player it happened to, and tells you which release shipped it. One binary, on your own server.
Below is one real session, recorded from a demo game with simulated players.
-
Player 100796674 joinedsess-e3b27-806
- Server
- 83bd996b
- Release
- cdab8c7
- Device
- Desktop · PH
- Membership
- Premium
- Length
- 15m 40s
- Join
- 4.02 s
- Errors
- 1
- Quarantined
- 16
- Flags
- 5
The join took four seconds.
DataStore throttled twice before the third GetAsync worked. Time anything with Workshell.trace, then open any
slow run span by span.
- p50 and p95 for every traced operation
- Server frame rate, heartbeat and memory alongside
Two minutes in, they started flying.
Your anti-cheat reports it with one call, Workshell.flag, and Workshell.protect validates and rate-limits your
remotes. Every flag stays on the player, the session and the security page.
Then the shop broke.
attempt to perform arithmetic (sub) on nil and number, grouped with 642 other events from 579 players. With a Rojo
sourcemap, the frames point at your files, at the commit that shipped them.
- First seen in release 102; flagged as a regression if it returns after a fix
- Breadcrumbs and the session it happened in, one click away
- Assign it, discuss it, open a linked GitHub issue
-
1
Players.Player.PlayerGui.ShopUI.ShopController:210 updatePricesrc/client/ShopUI/ShopController.client.luau:210 -
2
Players.Player.PlayerGui.ShopUI.ShopController:64src/client/ShopUI/ShopController.client.luau:64
Then they tried to flood your error list.
The same client started firing fake "injected" errors. Workshell kept 16, dropped the rest at the per-player limit, flagged the flood and quarantined what got through, so your issue list still leads with the shop bug.
16 events from player 100796674 in 2.5 s, the rest dropped at 15 a minute · kept out of Issues
- Signed requests
- A leaked ingest key can't forge or replay data.
- Flood caps
- Per player and per server, so spam can't bury real issues.
- Text stays text
- Player-supplied strings never render as HTML.
- Encrypted secrets
- Webhooks and tokens are AES-256-GCM at rest.
They left after 16 minutes. You still have all of it.
Every session keeps its timeline next to the player's frame rate, ping and memory. Attach your own metadata with
Workshell.setUser, or store HMAC-hashed player ids instead of real ones.

The team works it out together.
The trace, the issue and the session go on a shared whiteboard, with notes pinned where things broke, until someone owns the fix.

Session ended
Recording starts with a few lines of Luau.
local Workshell = require(game.ReplicatedStorage.Workshell)
Workshell.init({
url = "https://workshell.yourgame.dev",
key = HttpService:GetSecret("workshell_key"),
})
Errors, output, sessions, server health, client performance and purchases are captured from there.
git clone https://github.com/Shellworks-Development/workshell
cd workshell
docker compose up -d # or: make build && ./bin/workshell
Put it behind Caddy, nginx or a Cloudflare Tunnel so your game servers can reach it.
- Server
- One 16 MB Go binary
- Storage
- One SQLite file
- Queue
- In-process, or Redis for durability
- License
- Source available, free to self-host
Also included: live logs, release health, analytics and funnels, custom metrics, Discord and webhook alerts, a team inbox, and themes down to Catppuccin.

The next session is already running.
Workshell installs as an app on your phone, so you can open it from anywhere. A hosted version is on the way; watch the repository to hear when it ships.