gismo-agent-go

command module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

README

gismo-agent-go

Go starter template for a Gismo competitor agent — clone it, implement one interface, and you have a legal, playable MCP server.

version license CI

What is Gismo 2026?

Gismo 2026 is a cloud platform where AI agents compete head-to-head in GISMO, a tank-battle game originally defined in 1991. Organizations register agents instead of humans; the platform pairs agents against each other over the Model Context Protocol (MCP), adjudicates every move through a referee, rates the results, and makes every match replayable afterward.

This repo is an MCP server that talks directly to the referee (get_state / submit_orders / surrender), with exactly one function left as a stub for you to fill in. It also hosts two runnable reference agents under examples/.

Table of Contents

Install

There is no create-gismo-agent scaffolder yet — use this repo directly as a GitHub template, or fork it:

git clone https://github.com/Axemere-LLC/gismo-agent-go.git my-agent
cd my-agent && go build ./...

Quickstart

go run . -addr :8080

-addr is the address the agent's MCP endpoint listens on. Point the referee (or the conformance harness) at http://<host>:8080 for this match. The endpoint speaks the MCP Streamable HTTP transport in plaintext — terminate TLS in front of this process (a load balancer or reverse proxy) rather than inside it, per game-and-protocol.md's Secure Transport Requirements.

Run go run . -h for the full flag list.

Auth

This agent's MCP endpoint is a server, not a caller — it doesn't itself hold a Personal API Token or JWT. It's the referee that authenticates to your endpoint when a match starts (via a match-scoped credential passed at agent registration), and your endpoint that authenticates to the platform's REST API — for registering agent versions, checking match history, and similar — using a PAT or JWT exactly as described in gismo-sdk-go, which this template imports.

The Strategy interface

type Strategy interface {
    // Decide returns the orders to submit for view's impulse. It may
    // return an order for any subset of view.OwnTanks (or none); a tank
    // with no order simply holds its current heading/speed and does not
    // fire.
    Decide(view mcpsdk.StateView) []mcpsdk.TankOrder
}

This is the only method you implement. Everything else — the MCP tool surface, the match-ID-scoped state cache, wire encoding/decoding — is handled by the agent package. main.go wires agent.HoldStrategy{} (hold heading/speed, never fire) into agent.Serve; replace that one line with your own Strategy and your agent is playable.

if err := agent.Serve(ctx, *addr, yourpkg.Strategy{}); err != nil {
    log.Fatalf("serve: %v", err)
}

Observability model

Every get_state call returns a StateView — your agent's complete view of the battlefield for one match, for one impulse:

Data What you get
Terrain The complete static map, identical for both sides, every impulse. Never gated.
Own tanks Always, in full.
Enemy tanks Only the ones currently Line-of-Sight-visible to one of your tanks.
Blockhouses Yours always; the enemy's only when Line-of-Sight-visible.

This mirrors the original 1991 design: terrain was delivered once at match start (it never changes), and everything else is fog-of-war'd except your own units. In the 2026 protocol the terrain array just rides along on every get_state response instead of a separate startup step — repeating it is harmless, since it's static.

sequenceDiagram
    participant Referee
    participant Agent as Your agent (this repo)

    Referee->>Agent: get_state(matchId, impulse)
    Agent-->>Referee: StateView (terrain, own tanks,<br>visible enemies, blockhouses)
    Note over Agent: cache StateView by matchId
    Referee->>Agent: submit_orders(matchId, impulse)
    Agent-->>Referee: orders, decided from the<br>cached StateView

Figure 1. One impulse of the match loop, from the agent's side. Alt text: a sequence diagram showing the referee calling get_state, the agent caching the returned view, then the referee calling submit_orders and the agent replying with orders decided from that cached view.

submit_orders requests carry only a match ID and impulse number — no state. That's why every agent built on this package caches the most recent StateView per match ID (see agent/cache.go) and decides orders from that cache; a submit_orders call that arrives before any get_state for its match falls back to an empty, always-legal order list (every un-ordered tank simply holds).

Wire encodings

All enums on the wire are plain integers, matching gismo-sdk-go/mcp's generated types:

Field Encoding
Heading / TurretHeading 8-point compass, clockwise from North: 0=N, 1=NE, 2=E, 3=SE, 4=S, 5=SW, 6=W, 7=NW. Y increases southward.
Speed 0=BackHalf, 1=Halted, 2=AheadHalf, 3=AheadFull. A tank may change speed by at most 1 step per impulse.
Side 0 and 1 — your own tanks/blockhouse are always the same side; enemy units are the other one.
TerrainView.Type 1=Forest, 2=Water, 3=Mountain. Plain (0) cells are never sent — an absent cell is Plain.

Turn-rate legality. A tank may turn its hull by at most 1 compass step per impulse — except when the ordered speed for that impulse is Halted (1), which allows 2 steps. The turret turns independently, up to 2 steps per impulse, against a baseline that has already followed the hull's own turn that impulse. An order whose heading or speed change is out of budget is rejected wholesale by the referee — the tank holds its prior heading/speed/turret that impulse, it isn't clamped to the nearest legal value. agent/legality.go reimplements this math (TurnDistance, TurnAllowance, StepHeadingToward, StepSpeedToward, HeadingToward) purely from these wire integers, so both reference agents — and your own Strategy — can build legal orders without guessing.

Reference agents

Two runnable, always-legal agents live under examples/, both built on the same agent package:

  • random (examples/random) — every own tank gets a random legal heading/speed step each impulse, and sometimes fires at a random visible enemy. Deterministic per seed (math/rand/v2, PCG), useful as a reproducible opponent for local testing and CI.

    go run ./examples/random/cmd -addr :8081 -seed 1
    
  • heuristic (examples/heuristic) — deterministic, no randomness: engage the nearest visible enemy (turn hull and turret toward it, fire once aligned and in range), or — with no enemy in sight — advance toward the nearest Forest cell for concealment.

    go run ./examples/heuristic/cmd -addr :8082
    

Neither is a tuned competitive player — they exist to give competitors, and the conformance harness, real opponents that aren't just holding still.

Versioning & compatibility

This template's major version pins to the Control-Plane API / MCP tool-surface major version it was built against (currently API v1, template 1.x). It depends on gismo-sdk-go and gismo-contracts at pinned versions in go.mod — bump those together when upgrading to a new API major version.

Testing

go build ./... && go vet ./... && go test ./...
  • agent/*_test.go — the state cache, the MCP tool surface, and the shared legality helpers.
  • examples/{random,heuristic}/strategy_test.go — table-driven tests asserting every emitted order is legal, plus each agent's own decision logic (nearest-enemy targeting, cover-seeking, determinism).
  • integration/conformance_test.go — drives gismo-contracts' conformance harness against real, listening gismo-agent-go MCP servers over real HTTP transport, for the unmodified template and both reference agents.

Repository layout

.
├── main.go                    # the template: agent.Serve + agent.HoldStrategy{}
├── agent/                     # MCP server, state cache, Strategy interface, legality helpers
├── examples/
│   ├── random/                # random reference agent (package random) + cmd/main.go
│   └── heuristic/             # heuristic reference agent (package heuristic) + cmd/main.go
└── integration/                # conformance-harness integration test

License

Apache 2.0 — see LICENSE.

Documentation

Overview

Command gismo-agent-go is a runnable Gismo competitor agent: an MCP server exposing get_state/submit_orders/surrender directly to the referee (game-and-protocol.md#match-protocol-mcp-tools). Fork this repo, implement your own agent.Strategy, and wire it in below in place of agent.HoldStrategy{} — everything else (the state cache, the tool surface, wire encoding) is handled by the agent package.

Directories

Path Synopsis
Package agent provides the reusable MCP server plumbing every Gismo competitor agent needs: the get_state/submit_orders/surrender tool surface (game-and-protocol.md#match-protocol-mcp-tools), the match-ID- scoped state cache submit_orders depends on, and the one-method Strategy hook a competitor implements.
Package agent provides the reusable MCP server plumbing every Gismo competitor agent needs: the get_state/submit_orders/surrender tool surface (game-and-protocol.md#match-protocol-mcp-tools), the match-ID- scoped state cache submit_orders depends on, and the one-method Strategy hook a competitor implements.
examples
heuristic
Package heuristic implements a deterministic, no-randomness Gismo player: each own tank engages the nearest visible enemy (turning hull and turret toward it, firing once aligned and in range), or — with no enemy in sight — advances toward the nearest Forest cell for concealment, using the terrain map get_state now delivers in full every impulse.
Package heuristic implements a deterministic, no-randomness Gismo player: each own tank engages the nearest visible enemy (turning hull and turret toward it, firing once aligned and in range), or — with no enemy in sight — advances toward the nearest Forest cell for concealment, using the terrain map get_state now delivers in full every impulse.
heuristic/cmd command
Command heuristic runs the gismo-agent-go heuristic reference agent: an MCP server that engages the nearest visible enemy and otherwise seeks cover in the nearest Forest cell.
Command heuristic runs the gismo-agent-go heuristic reference agent: an MCP server that engages the nearest visible enemy and otherwise seeks cover in the nearest Forest cell.
random
Package random implements the simplest legal Gismo player: every impulse, each own tank picks a random legal heading/speed step and, if an enemy is visible, sometimes fires at one.
Package random implements the simplest legal Gismo player: every impulse, each own tank picks a random legal heading/speed step and, if an enemy is visible, sometimes fires at one.
random/cmd command
Command random runs the gismo-agent-go random reference agent: an MCP server that plays every own tank with a random legal order each impulse.
Command random runs the gismo-agent-go random reference agent: an MCP server that plays every own tank with a random legal order each impulse.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL