## Agent skills ### Issue tracker Gitea Issues at git.fossellini.top:SirStone/SirRoboGarage. See `docs/agents/issue-tracker.md`. ### Triage labels Default label vocabulary. See `docs/agents/triage-labels.md`. ### Domain docs Single-context layout. See `docs/agents/domain.md`. ### Folders ## SirGarage Directory Layout **SirGarage** (root directory) - `botname_garage/` — each bot gets its own directory following this pattern - src/ - botname.nim - botname.json - botname.sh - config.nim - botname/ — bot-specific modules - *.nim files - tests/ - test*.nim files - out/ - compiled binaries - prototypes or spikes for this bot (not at root) - docs/ — generic project documentation - tools/ — generic tools valid for all bots (battle runners, scripts, etc.) - common_libs/ — shared libraries valid for all bots - worktrees/ — git worktrees (gitignored) - AGENTS.md - CONTEXT.md - README.md - .gitignore ## How to use - These indications are for files that are always present, for files not mentioned here should be claer from context where belongs too. - Each bot development must be done in each folder in isolation. - If the bot requires extra folders during runtime, these must be created by the bot itself if not present already. ### NIM This repsoitory's main language is Nim, when you need to work with nim use the /nim mcp. --- ## Writing tests for a bot Framework lives at `common_libs/test_framework/`. Full docs: `common_libs/test_framework/README.md`. ### One-liner ```nim import test_framework/test_framework let r = runBattle(@[myBotDir, adversaryDir], rounds = 10) ``` `runBattle` blocks, returns `BattleResult`, raises on failure. ### Types ``` BattleResult → bots, rounds: seq[RoundResult], results: seq[BotResult], winners: seq[string] BotResult → name, totalScore, rank, firstPlaces, survivalCount RoundResult → round, results: seq[BotRoundResult] BotRoundResult→ name, score, rank, survived ``` ### Shared adversaries ```nim const tfAdversaries = currentSourcePath().parentDir.parentDir.parentDir / "common_libs" / "test_framework" / "adversaries" const sittingDuck = tfAdversaries / "SittingDuck" # passive — does nothing const oscillator = tfAdversaries / "OscillatorBot" # fights back ``` ### Setup (once per garage) **`tests/config.nims`** ```nim --path:"../../common_libs" # adjust depth to match garage location in repo ``` **`YourBot.nimble`** test task: ```nim task test, "Run integration tests": exec "nim c -r --path:../common_libs tests/test_basic_battle.nim" ``` ### Skip when JARs are absent (put before any suite block) ```nim import std/os if not existsEnv("TR_SERVER_JAR") or not existsEnv("TR_BATTLE_RUNNER"): echo "Skipping: TR_SERVER_JAR / TR_BATTLE_RUNNER not set" quit(0) ``` ### Offline parsing (no Java needed) ```nim import test_framework/battle_result let r = parseServerOutput(rawJsonLines) ``` ### Exceptions | Exception | Cause | |---|---| | `OSError` | Bot compilation failed | | `IOError` | Battle runner exited non-zero | | `TimeoutError` | Server startup (15s), compile (30s/bot), or battle runner timeout |