7e1f1483a4
- Document exception handling, zero-value BotResult trap, shared adversary bots - Add offline parsing example using parseServerOutput - Skip tests gracefully when JARs missing (guard before suite blocks) - Fix blocking readLine in runner_process.nim: poll with 50ms sleep + atEnd check (was preventing timeout enforcement, now blocks correctly during battle) - Add test task to QBot.nimble and config.nims setup docs to AGENTS.md - Add debug logging to TestBattleRunner for bot identity tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3.1 KiB
3.1 KiB
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)
- src/
- 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
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
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
--path:"../../common_libs" # adjust depth to match garage location in repo
YourBot.nimble test task:
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)
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)
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 |