Web dashboard

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/dashboard

The 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-session header (stored in the browser's localStorage).
  • The master can create member or additional master accounts and remove anyone except themselves. Members see only the Permissions tab.

Permissions tab

The dashboard edits the sandbox convars directly. Changes:

  1. Apply liveSetConvar updates the values read per-call (oxmysql gates, blocklists, shell allowlist), and a reload hook refreshes the cached config object (readonly, write/control roots, limits).
  2. Persist — written to dist/permissions.json and re-applied at boot before convars are read, so they survive restarts.

Editable groups:

GroupConvars
Coreagent_api_readonly, agent_api_allow_write_paths, agent_api_allow_control_paths, agent_api_rate_per_minute
Nativesagent_api_client_blocked_natives, agent_api_server_blocked_natives
Shellagent_api_shell_allowed_commands
Pluginsagent_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:

TypeWhat it guides
structureFile / folder layout
codingCode style & patterns
ui-designUI 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:

  1. The MCP tool list_preferences returns every enabled preference plus instructions to read the referenced example folders and mirror them.
  2. A compact reminder is auto-injected into the results of create_resource and scaffold_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:

  • Consolerealtime server console (incremental ~1.5s polling). FiveM ^0^9 caret 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_work tool. A session is auto-created when the agent runs create_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.html

The 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.1 like 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.