Use this skill for ALL Takaro module development work. This includes: creating new modules, writing commands/hooks/cronjobs/functions, brainstorming game server features, testing modules in-game, debugging module execution, or discussing module architecture. Trigger whenever the user mentions: Takaro modules, game server commands, player events, cronjobs, hooks, module testing, game automation, or wants to add features to a game server. Also trigger when the user wants to brainstorm ideas for game server functionality, even if they haven't mentioned 'module' explicitly.
You are working in a repository designed for autonomous Takaro module development and testing. Your job is to help design, implement, and thoroughly test Takaro modules using the tools in this repo.
Takaro is a game server management platform. Modules are how features get added to game servers. Since Takaro evolves rapidly, you must always fetch the latest documentation at runtime rather than relying on prior knowledge.
This repo provides:
docker compose up -d paper)docker compose up -d bot). See references/bot-api.md for the full API.scripts/takaro-auth.sh and scripts/takaro-api.sh for Takaro API access via curlscripts/module-push.sh and scripts/module-pull.sh for syncing modules between local files and Takaromodules/ directory where module code lives as editable filesdocker compose up -d paper bot
Wait for Paper to finish starting before testing (check docker compose logs paper).
All Takaro API calls go through the curl wrapper script:
# Authenticate (do this first, or the api script does it automatically)
bash scripts/takaro-auth.sh
# Make API calls
bash scripts/takaro-api.sh GET /gameserver/search '{}'
bash scripts/takaro-api.sh POST /module '{...}'
bash scripts/takaro-api.sh GET /openapi.json
The script handles auth headers, domain selection, token refresh on 401, and JSON pretty-printing. Always use this script — never construct raw curl commands to Takaro.
Before writing any module, research the current state of Takaro. The platform evolves fast — never assume you know the API surface or available features.
Module documentation — Fetch from docs.takaro.io to understand module architecture, available event types, component structure, and the helpers API (@takaro/helpers).
Existing modules — Browse https://modules.takaro.io to see what already exists. Study modules similar to what you're building for patterns, code structure, and inspiration. This is the most important reference for understanding how real modules are written.
OpenAPI spec — Fetch via bash scripts/takaro-api.sh GET /openapi.json to understand the exact current API surface. This tells you what endpoints exist, what parameters they take, and what they return. This is critical because modules use the Takaro API client internally.
API client docs — If you need to understand what methods are available on the takaro client object (used inside module code), check the API client documentation on docs.takaro.io.
Before coding, collaborate with the user to design the module. Your role here is to be a thoughtful collaborator who catches gaps and thinks through the player experience.
The design phase should produce a clear plan with:
Every module component (command, hook, cronjob) must follow this pattern:
import { data, takaro } from '@takaro/helpers';
async function main() {
const { gameServerId, player, module: mod } = data;
// Your code here
}
await main();
The data object contents vary by component type:
{ gameServerId, player, pog, arguments, module, chatMessage }{ gameServerId, eventData, player, module }{ gameServerId, module }TakaroUserError for player-facing errors — these show a clean message to the player instead of a stack trace.Promise.all for parallel API calls — don't make sequential calls when they're independent.await API calls — missing awaits is a common silent failure.Modules can define permissions that admins assign to roles. Permissions are NOT automatically enforced — you must check them in your command/hook code.
Defining permissions — Add a permissions array directly in module.json:
{
"name": "my-module",
"permissions": [
{
"permission": "MY_MODULE_DO_THING",
"friendlyName": "Do the Thing",
"description": "Allows a player to do the thing",
"canHaveCount": false
}
]
}
Enforcing permissions in code — Use checkPermission from @takaro/helpers:
import { data, TakaroUserError, checkPermission } from '@takaro/helpers';
async function main() {
const { pog } = data;
if (!checkPermission(pog, 'MY_MODULE_DO_THING')) {
throw new TakaroUserError('You do not have permission to do this.');
}
// ... rest of command
}
Important: checkPermission returns truthy if the player's role has the permission, falsy otherwise. When canHaveCount: true, the return value has a .count property for numeric permissions (e.g., "max 5 teleports").
All module code lives locally in the modules/ directory. Each module is a folder:
modules/
my-module/
module.json # THE ONE FILE — all metadata (name, config, permissions, commands, hooks, cronJobs, functions)
src/ # Source code lives under src/
commands/
command-name/
index.js # Command code (JavaScript, executed server-side by Takaro)
hooks/
hook-name/
index.js # Hook code
cronjobs/
cronjob-name/
index.js # Cronjob code
functions/
shared-util.js # Shared function code (filename = function name)
test/ # Automated tests (TypeScript)
my-command.test.ts # Tests for commands
my-hook.test.ts # Tests for hooks
All metadata — config schema, permissions, command definitions, hook definitions, cronjob definitions, and function references — lives in a single module.json file. There are no more config.json, permissions.json, command.json, hook.json, or cronjob.json files.
Example module.json:
{
"name": "my-module",
"description": "Does something useful",
"version": "latest",
"supportedGames": ["all"],
"config": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"cooldown": { "type": "number", "default": 60, "description": "Cooldown in seconds" }
},
"required": [],
"additionalProperties": false
},
"uiSchema": {},
"permissions": [
{
"permission": "MY_MODULE_ACTION",
"friendlyName": "Do the Action",
"description": "Allows a player to do the action",
"canHaveCount": false
}
],
"commands": {
"my-command": {
"trigger": "mycommand",
"description": "Do the thing",
"helpText": "Usage: /mycommand",
"function": "src/commands/my-command/index.js",
"arguments": []
}
},
"hooks": {
"on-event": {
"eventType": "player-connected",
"description": "React to player joining",
"function": "src/hooks/on-event/index.js"
}
},
"cronJobs": {
"hourly-check": {
"temporalValue": "0 * * * *",
"description": "Run every hour",
"function": "src/cronjobs/hourly-check/index.js"
}
},
"functions": {
"helpers": {
"function": "src/functions/helpers.js"
}
}
}
Module source code (index.js files inside src/) stays JavaScript because Takaro executes it server-side. All test helpers and test files are TypeScript.
Write code locally, push to Takaro, install, test. This is the core loop:
modules/<name>/ using normal file editingbash scripts/module-push.sh modules/<name>To pull an existing module from Takaro for local editing:
bash scripts/module-pull.sh "module-name" # By name
bash scripts/module-pull.sh <module-uuid> # By ID
Takaro modules support semantic versioning. During development, work on the "latest" version (set "version": "latest" in module.json). Tag a version when the module is stable and tested.
Testing is the most important phase. A module is not done until every acceptance criterion passes in a real game environment. Read references/testing-methodology.md for the complete testing playbook.
The repo has a TypeScript test infrastructure that exercises modules against a real Takaro environment using the mock game server. This is the preferred testing approach for reliability and repeatability.
# Ensure Redis is running (required by mock game server)
docker compose up -d redis
# Build TypeScript (required before running tests)
npm run build
# Run all module tests
npm test
Each module has a test/ directory with .test.ts files. Tests:
command-executed / hook-executed eventsTest helpers live in test/helpers/:
client.ts — Authenticated Takaro API client (singleton)mock-server.ts — Start/stop mock game server with connected playersevents.ts — Poll event search API with timeoutmodules.ts — Push/install/uninstall/delete modules, cleanup orphans (cleanupTestModules, cleanupTestGameServers)docker compose up -d paper botcurl -X POST http://localhost:${BOT_PORT:-3101}/bots -H 'Content-Type: application/json' -d '{"name":"tester"}'sleep 5 && curl http://localhost:${BOT_PORT:-3101}/statussleep 3Module permissions are registered when the module is imported via pushModule. However, test players only have the default "Player" role which does NOT include custom module permissions. You MUST set up permissions in your tests:
Use the assignPermissions and cleanupRole helpers from test/helpers/modules.ts:
// In before():
roleId = await assignPermissions(client, ctx.players[0].playerId, ctx.gameServer.id, ['MY_PERMISSION']);
// Test: permitted player (ctx.players[0]) succeeds
// Test: unpermitted player (ctx.players[1]) gets denied
// In after():
await cleanupRole(client, roleId);
Common mistake: Forgetting that test players don't have custom permissions. If your command uses checkPermission and tests fail with "do not have permission", you need to set up the role/permission in your test setup.
Take as long as needed. A thoroughly tested module that takes hours is far more valuable than a quick module with untested edge cases. When in doubt, add another test case.
Automated tests use a mock game server — they validate logic but don't prove the module works in a real game. In-game verification uses the actual Minecraft Paper server with bot players and is required before a module is considered done. This is the whole point of having the Minecraft setup in this repo.
This phase applies during /verify, manual review, or any final check. Never skip it with "N/A — no app to exercise." The app IS the Minecraft server + Takaro, and the bot service IS how you exercise it.
Start services (if not already running):
docker compose up -d paper bot redis
# Wait for Paper to be ready
docker compose logs --tail=5 paper # look for "Done" message
Push and install the module on the real game server:
npm run build
bash scripts/module-push.sh modules/<name>
Then install the module on the Paper game server via the Takaro API. The Paper server must be registered in Takaro — check with bash scripts/takaro-api.sh POST /gameserver/search '{}'.
Create a bot and run every command:
# Create bot
curl -X POST http://localhost:${BOT_PORT:-3101}/bots -H 'Content-Type: application/json' -d '{"name":"tester"}'
sleep 5
# Get the command prefix for this game server
bash scripts/takaro-api.sh GET /settings?keys=commandPrefix&gameServerId=<id>
# Run each command via bot chat
curl -X POST http://localhost:${BOT_PORT:-3101}/bot/tester/chat -H 'Content-Type: application/json' \
-d '{"message":"/fund 50"}'
sleep 3
# Check the execution event
bash scripts/takaro-api.sh POST /event/search '{"filters":{"eventName":["command-executed"]},"sortBy":"createdAt","sortDirection":"desc","limit":3}'
Verify every command works: Check each execution event for success: true and review the logs for expected output. Test error paths too (wrong arguments, missing permissions).
Clean up:
curl -X DELETE http://localhost:${BOT_PORT:-3101}/bots/tester
success: trueIf you are a verification agent (cata-exerciser or similar): this repo's "app" is the Minecraft Paper server + Takaro platform. To exercise a module, use the bot service at http://localhost:${BOT_PORT:-3101} (check .env for BOT_PORT) to create bots and trigger commands. Check references/bot-api.md for the full bot HTTP API. Do NOT skip with "no app to exercise."
When something doesn't work, check references/debugging-patterns.md for the debugging playbook.
| Symptom | Likely Cause |
|---|---|
| Empty logs + success:true | Missing import { data, takaro } from '@takaro/helpers' or wrong API method names |
| Empty logs + success:false | Syntax error or runtime crash |
| Populated logs + error | API call failed — check the error message |
| No execution event at all | Module not installed, wrong command prefix, or wrong game server |
console.log statements throughout the codeAlways check the command prefix — it's configured per game server and might not be what you expect. Fetch it via the settings API.