CASE STUDY 04 · GOV ROLEPLAY

A game world that sells, delivers and runs itself.

A GTA V roleplay server where the store, every delivery and the city itself run with nobody in the loop.

gov_loading · in game
The GOV loading screen: a rain-soaked estate at night, the GOV Roleplay mark, Welcome, operative, a mute key and the loading bar
The loading screen · the first thing every player sees, in GOV’s own style
ROLE
Founder; designed and built the technology
BUILT
Store, delivery, player and staff panels, character select, loading screen, AI city brain
STACK
Lua on QBox · React and TypeScript · Tebex · OpenRouter
STATUS
Running on the development server, ahead of its public launch
1,700PLAYERS ONLINE AT PEAK · KNG ESTATE
300STAFF TEAM, STARTED BY TWO FOUNDERS
26,000MEMBERS ON THE KNG DISCORD
01 · WHERE IT CAME FROM

A city, a faction inside it, then a server of its own.

GOV began as a storyline inside KNG Estate, the UK server Rikki founded. The figures above are KNG’s.

The Gov on an operation in KNG Estate: armed operatives in formation under a helicopter
KNG Estate · an operation in the city, in game
01
KNG ESTATE

A UK city, built from zero

Rikki’s UK roleplay city, No. 1 in the UK within a month and the home of everything that followed. The community side is on Communities.

The Gov’s leadership in suits, in game
The Gov’s leadership · in game
02
THE GOV

A faction that ran the story

Inside KNG, Rikki’s faction steered the city’s roleplay from behind the scenes. Players followed its storylines, and it grew into a server of its own.

The govroleplay.com home page: Power isn’t given. It’s built.
govroleplay.com · the store’s home page
03
GOV ROLEPLAY

The spin-off, systems first

The Gov became its own server. This time the technology was the point: a store that delivers on its own, and an AI that keeps the city’s story moving while the staff sleep.

02 · WHAT WE BUILT

Five screens, from loading in to running the city.

Real screens from the game, the store and the console; test accounts are marked. Pick a step.

gov_loading · in gamegov_multichar · test charactersGOV store · VIP pageGOV store · HQ panel · test accounttxAdmin · development server
The GOV loading screen: the GOV Roleplay mark over a rain-soaked estate, Welcome, operative, and the loading bar
Lines in the server’s own voice
GOV character select, test characters: three characters with job, ID, money and hours played; one marked incarcerated, one dead
Prison and death carry over
The VIP page on the GOV store: Bronze £15, Gold £40 and Silver £25 a month, with their perks£15, £25 or £40 a month
The GOV store HQ panel, test account: VIP rank Gold, active perks, an expiry date and two monthly vehicle picks
Set by the delivery, ends on its own
The GOV development server console in txAdmin: the city brain flags a near-empty server and sluggish economy, then broadcasts news and adjusts the economy

The city loads behind GOV’s own screen: rain on an estate, lines like “Welcome, operative”, a mute key. Built for the game’s older browser, it cleans up after itself when the player arrives.

Each player picks a character at border control: job, ID, money and hours played. A character in prison or dead says so before the player walks in.

Three clearance tiers a month, plus exclusive IDs and vehicles. Checkout runs through Tebex, which pays out and hands the order to the server.

What a player has bought, in one place: rank, perks, when they expire, vehicles, IDs and orders.

The AI city brain on the development server: it reads the city, finds what is wrong, asks the model for moves and runs only the ones it is allowed to.

03 · HOW A PURCHASE ARRIVES

Paid on the website, delivered in the game, with nobody in between.

Tebex takes the payment and runs one command on the server. Everything after that is GOV’s own code.

  1. THE PLAYERBuys GOV || Gold on the GOV store
  2. TEBEXTakes the payment, then runs one command on the server console
  3. gov_vip_deliverRuns only from the console, never for a player
    1. Sets the tier for the days bought
    2. Logs the sale with its transaction ID
    3. Tells the player in game: “Welcome to VIP GOLD!”
  4. LATER · ON A TIMERThe tier ends on its date, the player is told, the audit log records it
01

No one in the loop

A sale at any hour is delivered the moment Tebex confirms it: no ticket, no staff member, no wait.

02

A player can’t fake it

The command does nothing unless it comes from the server console, which only the store uses. A player who types it gets nothing.

03

It ends on its own

Expired tiers are removed on a timer, the player is told and the change is logged. Nobody keeps a spreadsheet of who paid until when.

gov_groups/server/tebex.lua · Lua · excerpt
RegisterCommand('gov_vip_deliver', function(source, args)
    if source ~= 0 then return end

    local citizenid = args[1]
    local tier      = args[2]
    local days      = tonumber(args[3])
    local txnId     = args[4] or 'unknown'
    local pkgName   = args[5] or 'VIP Package'
    local amount    = tonumber(args[6]) or 0

    local success, err = GroupService.setVipTier(citizenid, tier, days)
    if success then
        CreditService.recordPurchase(citizenid, txnId, pkgName, 0, amount)
        local src = Cache.citizenIdToSource[citizenid]
        if src then
            exports.qbx_core:Notify(src,
                ('Welcome to VIP %s!'):format(tier:upper()), 'success', 10000)
        end
    end
end, true)

The delivery command as it runs on the server, shortened: the error messages are cut and one long line is wrapped. The highlighted lines are the four steps in the drawing.

The same route assigns exclusive IDs and tops up GOV credit, each with its own command.

The city brain
04 · THE CITY BRAIN

An AI that keeps the city busy, inside rules it cannot break.

In the story GOV secretly runs the city. In the code an AI does, with moves players feel but can’t trace.

  1. THE CITY, NOWPlayers online, gangs active, minutes the police have sat idle, an economy index
  2. THREE MANDATESFaction health · economy · roleplay depth: what is wrong right now?
  3. MEMORYIts past moves, each marked “worked” or “backfired”
  4. THE MODELGemma 4 through OpenRouter, called from the server only; it answers with structured moves
  5. THE WHITELISTOnly allowed moves run, at most two a cycle
  6. FIVE MINUTES LATERThe change in players online scores the move, and the score goes back into memory

What the brain is allowed to do

What the brain is allowed to do
SWITCHED ON · WHAT PLAYERS SEE
dispatch_tipAn anonymous tip in police dispatch
economy_adjustThe drug market tightens or loosens
broadcast_newsA City Wire story on their phone
recruit_agentAn encrypted message from an unknown number
assign_missionA task for a recruited agent, paid in crypto
destabilise_factionA supply cut, a rival’s tip, planted evidence
PLANNED, SWITCHED OFF
spawn_eventWaits for the event system
plant_intelWaits for the link to the police computer
open_contractWaits for the dark market

Players with ten hours in the city can be recruited as GOV agents, five at a time at most. Nobody knows who else works for GOV: the paranoia is the feature.

05 · THE DECISIONS

Four choices, and what each one cost.

A game server is a hostile place: players test every command they can find. The choices follow from that.

Four decisions, what was chosen and what it cost later
ChoiceWHAT WE CHOSEWHAT IT COST LATER
01A small model inside a hard whitelist2026OpenRouterThe city brain runs on Gemma through OpenRouter’s free tier while the server is in development. The model is never trusted: only listed moves run, two per cycle at most, and it remembers eight events.The free tier hits its rate limit fast. And the model answers in two shapes, a list or an object holding a list, so the code accepts both.
02Delivery only from the consoleMARCH 2026The command that delivers a purchase checks who sent it. Anything but the server console gets nothing, so a player who learns the command cannot use it.Two resources once registered the same delivery commands. On 30 May they were folded into one, so a sale is delivered once.
03Built for the game’s old browserMARCH 2026The game draws its screens with Chromium 103. The build targets it, animates only position and opacity, and every screen clears its timers and media when it closes.Modern JavaScript failed without a word until the target was set. One line of CSS, color-scheme: dark, painted the whole screen black.
04No code we cannot readJUNE 2026On 2 June every encrypted third-party script was removed. What runs on the server is code we can open.That left clothing, jobs, the casino, the estate agent and the doors to rebuild or replace.
06 · UNDER THE HOOD

The requests, the data and one fix, read line by line.

Tebex sells and OpenRouter thinks. What GOV asks them, what comes back and what is written down; keys redacted.

01
AN API REQUEST

One call loads the whole shop

When the store opens, the browser asks Tebex for every category with its packages inside, in one request. The address carries the store’s public token: it can read the catalogue and open a basket, nothing more, so it is safe in the browser. Tebex wraps the answer in a data field; the code unwraps it, and if Tebex is down it logs the error and shows an empty shop instead of a broken page.

METHOD
GET: it reads, it changes nothing
ENDPOINT
/accounts/{token}/categories
QUERY
includePackages=1 puts each category’s packages inside it
AUTH
The public token, in the path; it lives in an environment file
webstore/src/utils/tebex.ts · TypeScript · excerpt, one long line wrapped
GET  https://headless.tebex.io/api
     /accounts/‹public token›/categories
     ?includePackages=1

export async function fetchCategories(): Promise<TebexCategory[]> {
    if (!token) {
        console.warn('[Tebex] No token configured — store will be empty.');
        return [];
    }
    try {
        const res = await fetch(
            `${API_BASE}/accounts/${token}/categories?includePackages=1`);
        if (!res.ok) throw new Error(`Tebex API ${res.status}`);
        const data = await res.json();
        return data.data ?? data ?? [];
    } catch (e) {
        console.error('[Tebex] Failed to fetch categories:', e);
        return [];
    }
}
  1. if (!token)No token configured: warn in the console and show an empty store.
  2. fetch(…)The request above: one GET, with the query that nests packages in categories.
  3. if (!res.ok)Any status outside 200–299 becomes an error that names the status code.
  4. data.data ?? dataUnwrap Tebex’s data envelope, or use the body as it is.
02
CATALOGUE DATA

Categories, items and variations

A category holds packages, and a package is what a player buys: a name, a price and a currency. The three VIP tiers are three packages in the VIP category, not one item with options; the site reads which medal to draw from the package name.

Exclusive IDs work the other way round. The package is the range (single digits, two digits, three), and the number the player picks is the variation: it travels with the basket line as variable_data. Numbers already sold come from a Firestore list, so they show as taken before anyone pays.

Sample response · the shape in webstore/src/types.ts · names and prices from the VIP page · IDs illustrative · trimmed
{
  "data": [
    {
      "id": 1001,
      "name": "VIP",
      "packages": [
        { "id": 2001, "name": "GOV || Bronze",
          "base_price": 15.00, "currency": "GBP",
          "category": { "id": 1001, "name": "VIP" }, … },
        { "id": 2002, "name": "GOV || Silver",
          "base_price": 25.00, "currency": "GBP", … },
        { "id": 2003, "name": "GOV || Gold",
          "base_price": 40.00, "currency": "GBP", … }
      ]
    }
  ]
}
webstore/src/App.tsx · TypeScript · the tier, read from the name
const getTierFromName = (name: string): 'bronze' | 'silver' | 'gold' => {
    if (name.toLowerCase().includes('gold')) return 'gold';
    if (name.toLowerCase().includes('silver')) return 'silver';
    return 'bronze';
};
Sample request body · the shape built by addToBasket() in tebex.ts · package ID illustrative
POST https://headless.tebex.io/api/baskets/‹basket ident›/packages

{ "package_id": 3001, "quantity": 1, "variable_data": { "chosen_id": "777" } }
03
AN AUTHENTICATED REQUEST

What the brain sends, and what it accepts back

Each cycle, the server posts the city’s state to OpenRouter’s chat endpoint. The key rides in an Authorization header and lives in a server setting, never in the code or a browser. The request asks for JSON only, and the brain’s instructions fix the shape: at most two action objects, each with a type, a mandate, a payload and a private reason.

The reply is checked twice. Did the request succeed? Does the content parse as JSON? Either answer “no” means no move this cycle, and the console says why.

gov_brain/server/ai.lua · Lua · excerpt
POST https://openrouter.ai/api/v1/chat/completions
Authorization: Bearer ‹key from the gov:openrouter_key server setting›
Content-Type:  application/json

local body = json.encode({
    model    = Config.Brain.Model,
    messages = { { role = 'system', … }, { role = 'user', … } },
    temperature      = 0.7,
    max_tokens       = 512,
    response_format  = { type = 'json_object' },
})
Sample reply · the shape set in the brain’s instructions · values from the console log of 3 June 2026 · fields with no record shown as …
[
  { "action_type": "broadcast_news", "mandate": "…", "event_type": "…",
    "payload": { "headline": "Unclaimed Cargo Found at Docks",
                 "body": "…", "tone": "neutral" },
    "reasoning": "…" },
  { "action_type": "economy_adjust", "mandate": "…", "event_type": "…",
    "payload": { "direction": "up", "magnitude": "small",
                 "reason": "Increase incentive for early session activity." },
    "reasoning": "…" }
]
04
EVENT TRACKING

Sales and moves, written down

Two logs make the system checkable. Each sale is a row keyed by its Tebex transaction ID, and that key is unique: if the same order arrives twice, it is recorded once.

Each brain move is a row holding the city as it was, the move and its payload. Five minutes later the same row gets a score from −5 to +5 and the change in players online. That score is what the brain reads back as “worked” or “backfired”.

gov_groups/server/credits.lua · Lua and SQL · excerpt, one long line wrapped
MySQL.insert.await([[
    INSERT IGNORE INTO gov_vip_purchases
        (citizenid, tebex_txn_id, package_name, package_id,
         amount, status, delivered_at)
    VALUES (?, ?, ?, ?, ?, 'delivered', NOW())
]], { citizenid, txnId, packageName, packageId, amount })

-- gov_groups/server/storage.lua: the table
tebex_txn_id VARCHAR(100) NOT NULL UNIQUE,
gov_brain/sql/gov_brain.sql · SQL · columns, trimmed and re-wrapped
CREATE TABLE IF NOT EXISTS `gov_brain_events` (
    `mandate`        VARCHAR(32) NOT NULL
                     COMMENT 'faction|economy|rp_depth',
    `city_state`     JSON NOT NULL COMMENT 'snapshot at decision time',
    `action_type`    VARCHAR(64) NOT NULL,
    `action_payload` JSON NOT NULL,
    `outcome_score`  TINYINT DEFAULT NULL
                     COMMENT '-5 to +5, NULL until scored',
    `player_delta`   SMALLINT DEFAULT NULL
                     COMMENT 'player count change after action',
    `created_at`     TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    …
);
05
A FAILED REQUEST, FIXED

Error 429, every minute

Two days after the brain was added to the development server, its live console repeated the same lines every minute: API error 429, then “AI returned no actions this tick”. The city was getting no moves at all.

A 429 means too many requests. The brain was on the model’s free tier, which caps how often it can be called, and it was calling once a minute. The status check printed the code, so the cause was clear from the console alone. The fix was one line: call every five minutes instead.

txAdmin live console · development server · 3 June 2026, before the fix · trimmed
09:25:07  [gov_brain] Consulting AI for mandates: faction, rp_depth
09:25:08  [gov_brain] API error 429:
09:25:08  [gov_brain] AI returned no actions this tick
09:26:08  [gov_brain] Consulting AI for mandates: faction, rp_depth
09:26:09  [gov_brain] API error 429:
09:26:09  [gov_brain] AI returned no actions this tick
gov_brain/config.lua · commit f1b5f954 · 3 June 2026, 10:46
-    TickInterval        = 60 * 1000,  -- 1 minute
+    TickInterval        = 5 * 60 * 1000,  -- 5 minutes (avoids free-tier 429s)
07 · DAY TO DAY

A small staff for the people, the system for the routine.

What a staff member does, what happens with nobody watching, and what the world is made of.

01
THE STAFF

One panel, powers by rank

  • Opens on F6, refused to anyone not staffCHECKED ON THE SERVER
  • Support: reports, players, teleport, reviveGRADE 0
  • Moderators: spectate, freeze, kickGRADE 1
  • Admins: jobs, bans and XPGRADE 2
02
THE SYSTEM

What runs on its own

  • Paid tiers and access end on their dateEXPIRY TIMER · PLAYER TOLD
  • Every sale and change written downAUDIT LOG
  • One permission spine for doors, targets and itemsGOV_GROUPS
  • Every brain decision logged and scoredGOV_BRAIN_EVENTS
03
THE WORLD

Clothing and uniforms

  • Nine open-source clothing packs for jobs and businessesFEMALE AND MALE · EIGHT OF NINE
  • No real-world brand logos, every source recordedSCOPE · SOURCING
  • Tested on the development server one group at a timePILOT CHECKLIST · ROLLBACK
  • Police and EMS uniforms streamed as their own packsCLOTHING RESOURCES
08 · WHO DID WHAT

A founder who builds what the community needs.

Rikki Chandler founded KNG Estate with one partner, led The Gov, then founded GOV Roleplay.

On GOV, Rikki designed the systems and built them by directing AI coding agents, reviewing every change before it reached the server: the store and its delivery, the player’s HQ, the staff panel, the character select, the loading screen and the city brain.

The gang, drug and crafting systems came from the server’s other developers. The clothing packs are open-source work by their makers, chosen and integrated for GOV.

  • Store and deliveryREACT · TYPESCRIPT · TEBEX · LUA
  • Player HQ and staff panelREACT · TYPESCRIPT · LUA
  • Character select and loading screenHTML · CSS · JAVASCRIPT
  • The city brainLUA · OPENROUTER · MYSQL
09 · RESULTS AND WHAT’S NEXT

What it proved, and what comes next.

Each figure carries its source. GOV’s own player numbers come after launch.

01
THE COMMUNITY · KNG

No. 1 in the UK within a month

1,700
players online at peak, on 2,000 slots
£50k
a month in revenue by month two
26,000
members on Discord

SOURCE · RIKKI CHANDLER’S CV, 2026

02
THE SYSTEMS · GOV

Selling without staff

1
command delivers every VIP sale, console only
6
moves the brain may make; three more built and off
2
moves a cycle at most, each scored after five minutes

SOURCE · GOV SERVER CODE: GOV_GROUPS, GOV_BRAIN

03
WHAT’S NEXT

Development to launch

  • Own replacements for paid, locked scripts: jobs, casino, estate agent, doors and clothing, all on the one permission spine
  • Switch on the brain’s last three moves as their systems arrive
  • A paid model tier for the brain at launch, in place of the free one

SOURCE · GOV SERVER-FILES CONTEXT

NEXT CASE Rocks Investments

Read the case
10 · CONTACT

Two doors. Pick yours.

Whether you are hiring or building, the first step is the same: one conversation with Rikki Chandler.

DOOR 1 · FOR HIRING TEAMSHiring for integration, solutions or implementation?

Rikki connects customers to systems, fixes what breaks and explains it so it sticks.

  • Technical integration and onboarding
  • Solutions and implementation
  • Customer engineering and support
Read the CVThe full story
DOOR 2 · FOR CLIENTSA business that should learn from its own data?

Tell us the one thing that should change. We start from that question and a written test of how we will know.

  • AI systems that run your operations
  • Product search and recommendations
  • Design, film and training for your team
Start a projectSee the work
STUDIO
ArtiFxn Design
FOUNDER
Rikki Chandler
BASED
Florianópolis, Brazil
TIME
UTC−3, working with teams across time zones

Every door leads to the same person.