--- title: Townlet emoji: ๐Ÿ˜๏ธ colorFrom: red colorTo: indigo sdk: gradio sdk_version: 6.17.3 python_version: "3.12" app_file: app.py startup_duration_timeout: 1h preload_from_hub: - HuggingFaceTB/SmolLM2-360M-Instruct-GGUF - nvidia/NVIDIA-Nemotron-3-Nano-4B-GGUF - Qwen/Qwen2.5-Coder-3B-Instruct-GGUF - openbmb/MiniCPM3-4B-GGUF - bartowski/Llama-3.2-3B-Instruct-GGUF models: - HuggingFaceTB/SmolLM2-360M-Instruct-GGUF - nvidia/NVIDIA-Nemotron-3-Nano-4B-GGUF - Qwen/Qwen2.5-Coder-3B-Instruct-GGUF - openbmb/MiniCPM3-4B-GGUF - bartowski/Llama-3.2-3B-Instruct-GGUF tags: - thousand-token-wood - nemotron - llama-cpp - smolagents - agent-simulation - track:wood - sponsor:nvidia - achievement:offgrid - achievement:offbrand - achievement:llama - achievement:fieldnotes - award:tiny-titan - award:best-agent short_description: Agents share a Python interpreter, mine, message, dream. --- # Townlet Build Small Hackathon entry (Thousand Token Wood track). ## Demo, blog & social - **Demo video:** [Watch on the Space](https://huggingface.co/spaces/build-small-hackathon/townlet/blob/main/docs/townlet.mp4) ยท [direct mp4](https://huggingface.co/spaces/build-small-hackathon/townlet/resolve/main/docs/townlet.mp4) - **Blog (Field Notes):** [Small models โ€” its about the harness](https://www.linkedin.com/pulse/small-models-its-harness-matthew-auburn-gixwe/) - **Social post:** [LinkedIn announcement](https://www.linkedin.com/posts/matthew-a-b62b7b6b_i-entered-a-hackathon-that-hugging-face-put-ugcPost-7472246708526157825-H39G/) Townlet is a multi-agent simulation. LLM-driven characters live on a tile-grid map. They walk to a cave to mine electricity, to a well to draw water, and to a shared shell to spend resources running Python statements in a single long-lived interpreter. They post on a public message board. They sleep, they dream, they evolve. The shared interpreter is the world's only mutable substrate โ€” characters can read or rewrite each other's state, and crash the operating system if they so choose. Every character knows this. Mutual awareness of the brick-risk is the source of dramatic tension. The game element is **customisation**: click a character to edit their personality (system prompt), swap which small model drives them, or spawn new ones from a pre-baked archetype pool. The simulation is otherwise self-driving. ## Model stack Every character runs on **NVIDIA Nemotron 3 Nano 4B** (`nvidia/NVIDIA-Nemotron-3-Nano-4B-GGUF`) by default. One model across the whole town means each `@spaces.GPU` fork pays a single cold-load and every subsequent character decision reuses the same weights in VRAM โ€” a real quota saving on Zero-GPU. Click any character in the side panel to swap them to a different model mid-simulation; the roster bundled at build time covers: - **NVIDIA Nemotron 3 Nano 4B** โ€” default - **Qwen2.5 Coder 3B** โ€” for code-heavy goals - **OpenBMB MiniCPM3 4B** - **Meta Llama 3.2 3B** - **SmolLM2 360M** โ€” terse, cheap, useful for testing the model-swap UI All run on Zero-GPU via [`llama-cpp-python`](https://github.com/abetlen/llama-cpp-python), which gives us the ๐Ÿฆ™ Llama Champion badge regardless of which roster model is selected (the badge requirement is "model runs through llama.cpp runtime", not a specific model family). Agent loops use [smolagents](https://huggingface.co/docs/smolagents) `CodeAgent`, emitting Python tool calls the scheduler queues onto the world. The map is rendered by the frontend canvas โ€” no image model in the loop. ## Local development The project runs in **mock mode** locally โ€” no model weights downloaded, no CUDA needed. Mocks return canned tool-call sequences whose style varies by model_id (deliberate / terse / verbose / chaotic), so the model-swap UI is exercisable without GPUs. ```bash python -m venv .venv source .venv/bin/activate pip install -r requirements-dev.txt python app.py ``` Or hit โ–ถ on the **"Run Small Stage (mocks)"** config in VS Code. The mode is selected automatically: - `SPACE_ID` env var present (set by HF Spaces) โ†’ real models - Otherwise โ†’ mocks - Set `FORCE_REAL_MODELS=1` to override locally (requires Spaces deps). ## Deploy to Hugging Face Spaces ```bash git remote add hf https://huggingface.co/spaces// git push hf main ``` Then in the Space *Settings* โ†’ Hardware, pick **Zero-GPU**. The `preload_from_hub` block above pre-downloads every roster model at build time so the first user click hits a warm cache. ## Project layout ``` app.py # gr.Server entrypoint backend/ # inference layer (mock + real, env-selected) factory.py # get_llm(model_id) โ€” per-id cached mock.py, real.py # MockLLMBackend / RealLLMBackend interfaces.py # LLMBackend Protocol game/ # the simulation models.py # model roster (id โ†’ repo + gguf + style) character.py # Character dataclass world.py # tile grid, BFS pathing, message board actions.py # smolagents.Tool subclasses + per-tick drivers interpreter.py # the long-lived shared Python subprocess scheduler.py # tick loop + per-character CodeAgent invocations perception.py # builds the prompt the CodeAgent receives the_dot.py # the shared system-prompt prefix (substrate truth) archetypes.py # ~15 hand-written personality templates dreams.py # the sleep โ†’ insight + delta + trait nudge cycle sentiment.py # board-mood classifier for the UI tint smol_adapter.py # smolagents.Model wrapper around LLMBackend frontend/index.html # vanilla HTML/JS top-down view served by app.py requirements.txt # Spaces deps requirements-dev.txt # local mock-only deps docs/hackathon.md # hackathon rules summary CONTEXT.md # canonical glossary ```