A human control panel at /agent_api/dashboard — master account, user management, and live sandbox permission editing.
agent_api serves a web dashboard from the same HTTP handler as the MCP endpoint. It's a separate, human-facing surface — it does not use the agent token. Operators sign in with their own accounts and manage the sandbox permission convars live.
http://127.0.0.1:30120/agent_api/dashboardThe URL is printed in the FiveM console on first start.
First run & the master account
- On the very first visit, with zero users, the dashboard shows a signup screen.
- The first account created becomes the master.
- Signup then closes permanently. There is no public registration once a master exists — the master creates every subsequent account from the Users tab.
This means the first person to reach the dashboard claims ownership. On a fresh install, open the dashboard and create your master account immediately.
Accounts
- Passwords are hashed with scrypt + a per-user salt (timing-safe compare). Stored in
dist/users.json(gitignored). - Sessions last 12 hours, carried in an
x-dashboard-sessionheader (stored in the browser's localStorage). - The master can create
memberor additionalmasteraccounts and remove anyone except themselves. Members see only the Permissions tab.
Permissions tab
The dashboard edits the sandbox convars directly. Changes:
- Apply live —
SetConvarupdates the values read per-call (oxmysql gates, blocklists, shell allowlist), and a reload hook refreshes the cached config object (readonly, write/control roots, limits). - Persist — written to
dist/permissions.jsonand re-applied at boot before convars are read, so they survive restarts.
Editable groups:
| Group | Convars |
|---|---|
| Core | agent_api_readonly, agent_api_allow_write_paths, agent_api_allow_control_paths, agent_api_rate_per_minute |
| Natives | agent_api_client_blocked_natives, agent_api_server_blocked_natives |
| Shell | agent_api_shell_allowed_commands |
| Plugins | agent_api_plugin_esx_enabled, agent_api_plugin_oxlib_enabled, agent_api_plugin_oxmysql_enabled, agent_api_plugin_oxmysql_readonly, agent_api_plugin_oxmysql_allow_statements, agent_api_plugin_esx_blocked_methods, agent_api_plugin_oxlib_blocked_methods |
Booleans render as toggles, enums as selects, CSV/int as text fields. Editing one and hitting Save flips it for the live runtime instantly — no resource restart needed.
See Configuration for what each convar does.
Preferences tab (master only)
Teach the agent how you like resources built so its output stays consistent with your conventions — across Lua and UI. Each preference is one of three types:
| Type | What it guides |
|---|---|
structure | File / folder layout |
coding | Code style & patterns |
ui-design | UI stack & visual style |
Each item has a free-text description and an optional example folder, picked through a server-backed, read-only folder browser (list resources → drill into subfolders, sandbox-checked — it never reads file contents, only directory names). Toggle items on/off, edit, or delete.
Preferences are file-backed in dist/preferences.json (not hardcoded) and reach the agent two ways:
- The MCP tool
list_preferencesreturns every enabled preference plus instructions to read the referenced example folders and mirror them. - A compact reminder is auto-injected into the results of
create_resourceandscaffold_fivem_resource_workflow(the "starting new work" tools), so the agent checks them at the right moment without noise on every edit.
The scaffold grill calls list_preferences first and asks, per type, whether to adopt your preference as the guideline for the new resource.
Skills tab (master only)
Upload your own custom skill (write markdown inline or upload a .md file) and bind it to the MCP actions that should trigger it — by tool name (e.g. write_file), by category (write, lifecycle, scaffold, ui, native, player, shell, plugin), or both. When a bound tool runs, the skill's body is injected into that tool's result as an APPLIED SKILL block, so the agent follows it in context.
Skills are file-backed: metadata in dist/skills.json, each body in dist/skills/<id>.md. The MCP tool list_skills returns them for inspection, but you rarely need it — binding + auto-injection is the intended path.
Monitor tab (master only)
The master's default landing tab — two read-only views into what's happening, served from the same handler:
- Console — realtime server console (incremental ~1.5s polling). FiveM
^0–^9caret colors are parsed (txAdmin-style) with the color reset at end of each line, each resource/channel prefix gets its own stable hashed color, and prefixes align in a fixed-width column. Toggle Live off to freeze it. - Audit — the trail of every agent tool call (timestamp, tool, result code, hashed caller) from
dist/audit.log, with a tool filter, OK/error filter, sortable columns, and pagination over the last 500 calls.
This is the human-facing counterpart to the tail_console / scan_errors tools and the agent://console MCP resource.
Sessions tab (master only)
A per-resource task board the agent publishes, plus a way to send the agent targeted requests. Polls every ~5s.
For each session you see:
- Current task and a todo list (pending / in-progress / done) the agent writes via the
track_worktool. A session is auto-created when the agent runscreate_resource. - A file tree of the resource (recursive, read-only, sandboxed; skips
node_modules/ dot-dirs, bounded depth). - Any requests queued against that resource and their status.
Click the ✎ icon on any file or folder — or Ask about resource — to open a prompt modal. The text is queued as a request { resource, path | null, prompt } (a null path means the whole resource). The agent is told about pending requests through a short line injected into its next tool result, then reads them with get_requests and closes them with resolve_request.
State is file-backed in dist/tasks.json and dist/requests.json (gitignored).
The agent only acts on a request while it is running (injection rides on its tool calls). If no agent session is active, requests wait in the queue — pair with a polling loop if you want them picked up hands-free.
Relationship to server.cfg
Convars set in server.cfg are the boot defaults. The dashboard layers dist/permissions.json on top of them at startup. If you set the same convar in both, the dashboard override wins (it's applied after the cfg is read, and again on every save). To reset to your server.cfg baseline, delete dist/permissions.json and restart.
Build
The dashboard UI is a Vite + Vue 3 project under dashboard/, built to a single self-contained dist/dashboard/index.html that the resource serves verbatim.
npm run dashboard:install # once
npm run dashboard:dev # hot-reload dev server (proxy API to your FiveM host)
npm run dashboard:build # → dist/dashboard/index.htmlThe built file is committed to the repo, so a fresh ensure agent_api serves a working dashboard with no build step. Maintainers re-run dashboard:build and commit the result when the UI changes.
Security notes
- The dashboard binds to
127.0.0.1like the rest of the HTTP surface. For remote access, SSH-tunnel port 30120. - A dashboard session can change every sandbox gate — treat master credentials like server admin credentials.
- The agent token and dashboard accounts are independent. Rotating one does not affect the other.