Skip to content

AI assistants

Every page here is written once, as Markdown, and published twice: as the page you are reading and as plain text an assistant can read whole. Point a coding agent at the files below and it works from the same reference you do - the real syntax of every function, the real keys of every item - instead of what it remembers of some other game’s API.

Every page has a Markdown twin. Replace the trailing / of a page’s address with .md: /lua/server/functions/setspawninfo/ is also /lua/server/functions/setspawninfo.md - the source of the page, without the navigation, in one request. Names are lowercase in addresses (SetSpawnInfosetspawninfo). An agent that looks pages up as it works should fetch these, not the HTML.

The files follow llmstxt.org and are built from the same source as the site on every publish, so they cannot fall behind it. Nothing here is behind a login or a rate limit; a plain curl gets any of them.

A game mode is one Lua file next to the server, named in its server.toml (Setting up). Two files in the folder the mode lives in - the server’s gamemodes/ folder or a repository of its own - turn a coding agent from a guesser into a colleague who has read the manual:

The definitions. The server’s gamemodes/ folder already carries a .luarc.json that points the Lua language server at sdk/KcdMp.d.lua. For a mode in a folder of its own, copy the file (or download it, above) next to the script and add:

{ "runtime.version": "Lua 5.4", "workspace.library": ["."], "workspace.checkThirdParty": false }

An editor with the “Lua” extension (sumneko / LuaLS) then completes every name and flags one that does not exist; an agent working in the folder reads the same file and can run the same check.

The instructions. Save this as CLAUDE.md - Claude Code reads it at the start of every session; the same file as AGENTS.md serves Codex, Cursor and the others. It tells the agent where the API is, what it must not invent, and the handful of rules a mode lives by.

# <mode name> - a KCD:MP game mode
This is a game mode for KCD:MP (KCD Multiplayer), the multiplayer platform for Kingdom Come: Deliverance II:
one Lua 5.4 script the dedicated server runs. The server calls the script's callbacks (`OnPlayerConnect`,
`OnPlayerDeath`, `OnTick` ...) and the script calls the server's functions (`SendClientMessage`, `SetSpawnInfo`,
`CreateActor` ...).
## The API is documented, never guessed
- `KcdMp.d.lua` in this folder is the whole game mode API - every function, callback and constant with its types
and documentation, in Lua language server form. Read it before writing; it is the reference that is always at hand.
If it is missing, fetch https://docs.kcd-mp.com/KcdMp.d.lua.
- For the guides and the examples read https://docs.kcd-mp.com/llms-small.txt once per session: how the server runs a
script, the tick, combat, an example for every callback and function, the client API, the map of the reference lists.
- For one function or callback fetch its page as Markdown: https://docs.kcd-mp.com/lua/server/functions/<name>.md
or https://docs.kcd-mp.com/lua/server/callbacks/<name>.md, the name in lowercase (`SetSpawnInfo``setspawninfo.md`).
- Only the functions and callbacks the documentation lists exist. There is no `Player` object, no event emitter,
no `require("KcdMp")`, no API from any other game. If a function is not on https://docs.kcd-mp.com/lua/server/
it does not exist - say so rather than inventing one.
- Keys of game things - items, souls, buffs, meshes, outfits, animation clips, sounds, doors - come from the
reference lists (https://docs.kcd-mp.com/reference/; one file per list at
https://docs.kcd-mp.com/_llms-txt/reference-<list>.txt - they are big, fetch the one you need). Never make a
key up. Keep the name or the GUID in the script, not the numeric id: ids shift with game patches.
## How the server runs the script
- Plain Lua 5.4 with the standard library; one file, or a folder of files joined by `require` (relative to the
script). The API is globals the server registers before the script runs; the callbacks are globals the
script defines.
- Everything runs on the simulation thread, one tick at a time, 30 times a second. No threads, no locks, no
races - and a slow callback stalls every player. Heavy work goes on a timer (`SetTimer`), not in `OnTick`.
- `pid` is a player, `0` to `GetMaxPlayers() - 1`, reused after a disconnect: keep the pid while a player is on,
check `IsPlayerConnected(pid)` before trusting one kept across ticks. `id` is a world entity (a horse, a
prop, an NPC actor), `nil` from every getter once it is gone.
- Positions are metres in the level's world space (`z < 0` = on the terrain), yaw is degrees, colours are
`0xRRGGBBAA` (the constants name the usual ones), times are milliseconds, the world clock is hours.
- A bad key or id never raises: the call returns `nil` or `false` and the server log says why. Check returns.
- A runtime error inside a callback is logged and that callback's effect is skipped; a syntax error stops the
server at start (after a `/reload` it leaves the built-in freeroam in charge until the next reload).
- Chat commands arrive in `OnPlayerCommandText(pid, cmd, args)`; parse `args` with `sscanf(args, "ud")`
(`u` a player, `d` a whole number, `f` a number, `s` a word, `z` the rest of the line, `?` optional). Return
`true` when handled, `false` to let the server's built-in commands have it.
- `Log(...)` writes to the server log with a `[lua]` prefix.
## Working here
- The mode is `<mode>.lua` in this folder. `server.toml` names it under `[gamemode] script`; `watch = true` there
reloads it on save, `/reload` in chat does the same by hand.
- Before calling a change done, run the Lua language server's check over the folder
(`lua-language-server --check .` - `.luarc.json` points it at `KcdMp.d.lua`): an unknown name or a wrong
argument type is a diagnostic there and a silent `nil` on the server. Zero diagnostics is the bar.
- Run a local server with `KcdMp.Server --gamemode <mode>.lua` and read its log for `[lua]` lines.
- The modes that ship with the server - `freeroam.lua`, `duel_arena.lua` and the `marker` example with its
client half - are the style to follow.

Then ask for the mode in plain words - a capture-the-flag with two teams, a flag prop in each camp, ten minutes on the HUD clock - and the agent fetches what it needs. Claude Code fetches the URLs itself; for an assistant without web access, paste llms-small.txt into the conversation, or keep a copy beside the mode:

Terminal window
curl -O https://docs.kcd-mp.com/llms-small.txt

A C# plugin project works the same way with sdk/KcdMp.Api.dll and its .xml in place of the definitions file - the agent reads the interfaces and their summaries from the project’s reference - and c-plugins.txt in place of the Lua API in the instructions.

  • ChatGPT, Gemini, a chat window: attach or paste llms-small.txt; add the reference list the mode needs.
  • Cursor: Settings → Indexing & Docs → Add Doc with https://docs.kcd-mp.com/llms-small.txt, then @Docs in a prompt.
  • Anything that crawls: robots.txt allows every agent, and /sitemap-index.xml lists every page.