The Problem

Developers who want a ready‑to‑run simulation of autonomous AI agents need a full stack (frontend, backend, vector store, LLM integration) that can be deployed locally or to the cloud without stitching together disparate pieces. Maintaining the wiring between the game engine, Convex database, and LLM calls is error‑prone, especially when the codebase grows.

What This Does

ai-town supplies a complete starter kit that runs a Pixi‑JS front‑end, a Convex‑backed simulation engine, and plug‑in support for OpenAI, Ollama or other chat models. The backend lives under convex/ and includes generated API stubs (convex/_generated/api.js), game‑logic modules (convex/aiTown/*.ts), and utility libraries (convex/util/*.ts). The client lives in src/ with React components such as src/components/Game.tsx and src/components/PlayerDetails.tsx. Docker support (Dockerfile, docker‑compose.yml) lets you spin up the whole stack with a single docker compose up.

How It Is Wired

  1. Entry point – The server starts from convex/_generated/server.js, which registers the generated Convex API (convex/_generated/api.d.ts).
  2. Main simulation – convex/aiTown/main.ts exports startEngine, stopEngine, and kickEngine. startEngine constructs a Game (convex/aiTown/game.ts) and begins ticking via Game.scheduleOperation.
  3. Game loop – Game.tick (in convex/aiTown/game.ts) calls Game.startOperation, which eventually invokes convex/aiTown/agent.ts → Agent.tick → Agent.runAgentOperation. The agent uses convex/util/llm.ts for chatCompletion and tryPullOllama to talk to the configured LLM.
  4. Database access – All state reads/writes go through Convex query/mutation contexts (QueryCtx, MutationCtx). Functions like allocId, insertInput, and loadWorldStatus (in convex/aiTown/*.ts) are the primary callers of the database. The most fan‑in module is convex/util/llm.ts (16 functions, 7 classes, called from 3 files).
  5. Client‑side sync – React hooks in src/hooks/ (useHistoricalValue.ts, useWorldHeartbeat.ts) subscribe to Convex queries and push user input via src/hooks/sendInput.ts. The UI components render the game state supplied by those hooks.
  6. Hot spots – The import graph shows 13 circular dependencies, notably among convex/aiTown/player.ts, convex/aiTown/conversation.ts, and convex/aiTown/game.ts. convex/aiTown/ids.ts is a hub with 24 inbound imports, meaning changes there have a wide blast radius.
  7. External calls – Only two functions make outbound network requests: the LLM helpers in convex/util/llm.ts and the music generation call in convex/music.ts.

How To Use It

# Clone the repo (use the exact URL)
git clone https://github.com/moses-y/ai-town.git
cd ai-town

# Install Node dependencies
npm ci

# Run locally with Convex dev server (requires a free Convex account)
npx convex dev

# In another terminal, start the React front‑end
npm run dev   # defined in package.json scripts

Docker alternative

docker compose up --build

No additional environment files are committed; the README directs you to configure an LLM key in the Convex dashboard (convex/http.ts reads process.env.OPENAI_API_KEY when using OpenAI). The fly/ folder contains fly.toml for Fly.io deployment, but no secrets are stored in the repo.

Real‑World Use

A product team can fork this repo, replace the default llama3 prompt files in convex/aiTown/agentDescription.ts, and point convex/util/llm.ts at their own hosted LLM. The front‑end can be embedded in an existing React portal by importing src/components/Game.tsx. All state changes flow through Convex, giving automatic scaling and ACID guarantees for the simulation.

Code Health & Issues

  • High – Missing CI – No workflow builds/tests the 124 source files.
  • High – No build gate for Docker – Image is never validated by CI.
  • Medium – Dependabot disabled – No automated version bump for 42 dependencies.
  • Medium – Base image not pinned – ubuntu:22.04 used without digest.
  • Medium – Large binary in repo – src/editor/tilesets/Modern.png (5.4 MiB).
  • Medium – No non‑root user – Dockerfile runs as root.
  • Medium – Sparse test coverage – 6 test files for 124 source files (≈5 %).

The static analysis also flags 13 import cycles (e.g., convex/aiTown/player.ts ↔ convex/aiTown/game.ts) and duplicated 6‑line code blocks across generated and hand‑written files, which increase maintenance burden.

The Bottom Line

ai-town delivers a functional, Docker‑ready AI simulation stack with clear separation between front‑end, game engine, and LLM integration. It is suitable for teams that need a quick prototype or a base to build custom agent behavior. However, the codebase suffers from circular imports, limited automated testing, and missing CI/CD safeguards, so a production deployment should first address those health concerns.