Spaces:
Sleeping
A newer version of the Gradio SDK is available: 6.19.0
GODSEED β Architecture Contract (v1, June 12 2026)
This file is the single source of truth for the parallel build. Every builder agent reads this FIRST and writes ONLY the files it owns (see File Ownership). Interface drift gets fixed by the integrator β but don't create drift: when in doubt, follow the schemas here exactly.
One-liner
Type a wish β a tiny Nemotron god plans aloud and terraforms ONE persistent WebGL planet shared by every visitor. Tagline: "Nine billion parameters. One shared world." Track: π Thousand Token Wood. Hackathon: Build Small (Gradio + HF). Deadline June 15.
Awards targeted: NVIDIA team-judged RTX 5080 (Nemotron load-bearing), Best Agent (visible plan-act-observe + published traces), Bonus Quest (6/6 badges), Modal slot (LoRA), TTW podium, Community Choice (shared world farms likes), Judges' Wildcard.
Non-negotiable design rules
- The "her" pattern (org-celebrated judge taste): the deterministic engine owns ALL world state and facts. The LLM only interprets the wish, narrates, and picks tool calls from a small DSL. The LLM never computes geometry, never owns state.
- One wish at a time. A single serialized queue. Visitors see their queue position. Latency is reframed as liturgical pacing ("the god grants one wish at a time").
- The landing page must be gorgeous with ZERO GPU. The planet renders client-side from the world-state JSON. Live inference is the second act. Judges often evaluate while GPUs sleep.
- Determinism end-to-end. Every feature carries a seed; the renderer is a pure function of the ordered feature list. This makes the Genesis Log replay (see below) free.
- Moderation before execution. One swastika-shaped forest during judging week ends every award.
- Models β€32B total params (hard hackathon rule). Only ONE model in the app.
- NAMING: the wish archive page is called "Genesis Log" β NOT "Book of Wishes". A rival space (aether-garden) shipped a "Book of Ages" on June 11; avoid any perceived imitation. Also avoid the words "remember/remembers" in copy β that's their tagline. Our frame: creation, not memory. The god makes; it does not reminisce.
Repo layout & FILE OWNERSHIP (critical β do not touch files you don't own)
godseed/
ARCHITECTURE.md (this file β read-only for everyone)
app.py β AGENT B (server)
requirements.txt β AGENT B
README.md β AGENT B (HF Space card w/ full YAML tags)
Dockerfile.fallback β AGENT B (in case sdk:gradio health-check fails)
server/ β AGENT B (sse.py, persistence.py, schemas.py, ratelimit.py)
engine/ β AGENT A (world.py, tools.py, queue_worker.py, moderation.py, summary.py, genesis.py)
mind/ β AGENT C (planner.py, backends.py, prompts.py, grammar.gbnf, mock_scripts.py)
web/ β AGENT D (index.html, style.css, main.js, book.html, planet/*.js, lib/ vendored three.js, mock/)
tests/ β test_engine.py (A), test_api.py (B), test_mind.py (C)
tools/ β AGENT D (shot.mjs β headless screenshot harness, adapted from glassblower)
traces/ (runtime output β wishes.jsonl; gitkeep only)
Reference code to LIFT (read these, reuse patterns):
/Users/andrescarreon/Documents/dev/buildsmall/glassblower/app.pyβ FastAPI + mount_gradio_app + StaticFiles + SSE withX-Accel-Buffering: noheader. Proven pattern./Users/andrescarreon/Documents/dev/buildsmall/glassblower/web/main.js+web/lib/β Three.js setup, vendored libs, postprocessing/bloom wiring./Users/andrescarreon/Documents/dev/buildsmall/glassblower/tools/shot.mjs,shot-live.mjsβ headless Playwright screenshot harness.- Glassblower renderer learnings (hard-won): low transmission + strong emissive for visible
glowing material (full glass transmission reads as invisible); selective bloom threshold β0.66;
decouple sim from rAF with fixed-step
seek()/tick()(headless Chromium throttles rAF).
World model
The world is an append-only ordered list of Features. World-at-epoch-N = features[0..N). The renderer derives ALL geometry deterministically from this list. Sky/weather are last-write-wins (but still stored as features so replay works).
Feature (canonical JSON)
{"id": "f_000017", "wish_id": "w_000005", "tool": "spawn_flora",
"args": {"lat": 12.0, "lon": 40.0, "radius_deg": 8, "kind": "glowgrass", "density": 0.7, "hue": 160},
"seed": 1830293847, "t": 1718200000.0}
seed is assigned by the engine: seed = crc32(f"{wish_id}:{call_index}") & 0x7fffffff. The JS
renderer uses the same seed with mulberry32 for all scatter/noise decisions of that feature.
Tool DSL β 11 tools (GBNF-friendly: flat args, numbers + enums + short strings)
The base table below is the original 9; the City Update added
spawn_lifeand the Town Mode update addedbuild_district+place_road(full specs in those sections). The live surface is 11 tools β seeengine/tools.py(TOOL_NAMES) for the source of truth.
| tool | args (ranges clamped by engine) |
|---|---|
raise_terrain |
lat β85..85, lon β180..180, radius_deg 2..45, height 0.01..0.12 (planet radii), roughness 0..1 |
lower_terrain |
lat, lon, radius_deg 2..45, depth 0.01..0.10, roughness 0..1 |
spawn_flora |
lat, lon, radius_deg 1..30, kind β trees|glowgrass|mushrooms|vines|flowers|reeds, density 0..1, hue 0..360 |
place_structure |
lat, lon, kind β lighthouse|monolith|shrine|village|beacon|arch|tower|warehouse|cafe, scale 0.5..2.0, hue 0..360 |
place_water |
kind β stream|pool, path [[lat,lon] Γ1..5] (stream: 2..5 waypoints, becomes glowing spline on the surface β NOT carved; pool: path[0] center), radius_deg 1..10 (pool only), hue 160..260 |
set_weather |
kind β clear|rain|snow|embers|mist|storm, intensity 0..1 |
set_sky |
palette β dawn|dusk|night|aurora|ember|void|gold, star_density 0..1, moons 0..3 |
inscribe_wish |
text β€90 chars (the wish, possibly poeticized), style β orbit|stone |
spawn_life |
lat, lon, radius_deg 1..20, kind β carts|birds|fireflies, count 1..12 (integer), hue 0..360 |
Engine clamps out-of-range numbers (doesn't reject) and rejects only unknown tools/enums with a terse observation string the model can react to.
Genesis state (epoch 0 β MUST match between engine and renderer mock)
[
{"id":"f_000000","wish_id":"genesis","tool":"set_sky","args":{"palette":"void","star_density":0.9,"moons":1},"seed":7,"t":0},
{"id":"f_000001","wish_id":"genesis","tool":"raise_terrain","args":{"lat":12,"lon":40,"radius_deg":28,"height":0.05,"roughness":0.7},"seed":11,"t":0},
{"id":"f_000002","wish_id":"genesis","tool":"place_structure","args":{"lat":14,"lon":38,"kind":"monolith","scale":1.4,"hue":270},"seed":13,"t":0},
{"id":"f_000003","wish_id":"genesis","tool":"inscribe_wish","args":{"text":"speak, and it will be made","style":"orbit"},"seed":17,"t":0}
]
A barren obsidian world, one monolith, an orbiting invitation. Gorgeous and zero-GPU by design.
Agent protocol (the Mind)
Real plan-act-observe loop (Best Agent evidence), GBNF/JSON-constrained:
- Reading (free-text generation, streamed token-by-token, β€80 tokens): the god interprets the wish aloud β mood, intent, plan sketch. This is the "plans aloud" wow moment.
- Turn loop (grammar-constrained JSON, max 7 turns). Each turn the model emits exactly one of:
{"thought": "β€160 chars", "call": {"tool": "...", "args": {...}}}{"thought": "β€160 chars", "done": true, "epitaph": "β€120 chars"}After each call the engine returns a terse observation ("ok: mountains risen at (12,40)"/"rejected: unknown kind 'cactus'") which is appended to the context before the next turn.
Planner interface (AGENT C implements; AGENT A's queue worker drives it):
class Planner:
async def grant(self, wish: str, world_summary: str,
act: Callable[[dict], Awaitable[str]], # executes a tool call, returns observation
emit: Callable[[dict], Awaitable[None]] # streams SSE events (thought_token, etc.)
) -> WishTrace
Backends behind GODSEED_BACKEND env (mind/backends.py):
mockβ deterministic keywordβplan scripts with seeded variety + artificial token delays. Local dev + headless demos. Must exercise every tool.llamacppβ llama-cpp-python, NVIDIA Nemotron-3-Nano-4B GGUF Q4_K_M (~2.5GB, fits free 16GB CPU tier), native GBNF grammar. This is the v0 SHIP backend (earns Off the Grid + Llama Champion badges; real model, no GPU bill). Model path viaGODSEED_GGUFenv; download in code from HF hub if missing.zerogpuβ transformers +@spaces.GPU, NVIDIA Nemotron-Nano-9B-v2 (the LIVE backend; in-tree nemotron_h class, trust_remote_code=False, kernel-free native Mamba-2 path). Constrained decoding via prompt + JSON validation + 1 retry (no GBNF in transformers; keep a strict parser). NOTE (June 12): the Nemotron-3 4B/30B repos hard-require remote code + mamba-ssm kernels, which cannot import on the ZeroGPU image β they are NOT usable on this backend.
Moderation (engine/moderation.py, AGENT A): layered β (1) charset/length limits (β€140 chars,
printable); (2) wordlist/regex for slurs, sexual content, hate symbols; (3) LLM yes/no judgment via
the same backend (grammar-constrained {"allowed": bool, "category": "..."}), default-deny on
uncertainty or parse failure. Rejections are poetic but final ("The god declines this wish.").
Queue
engine/queue_worker.py (AGENT A): single global asyncio worker. submit(text, client_id) β (wish_id, position). Caps: 1 pending wish per client, 3/hour per client (B's ratelimit.py supplies
client_id from cookie+IP hash), queue max 50 ("the god is overwhelmed; return at dusk"). Worker:
pop β moderate β planner.grant() β persist trace β emit wish_granted.
SSE protocol (server/sse.py β single /api/stream broadcast to all clients)
{type:"hello", world_version, epoch}
{type:"queue", length, current: {wish_id, text_preview} | null}
{type:"wish_started", wish_id, text}
{type:"thought_token", wish_id, text} β streamed reading + turn thoughts
{type:"tool_call", wish_id, call_index, tool, args}
{type:"world_delta", feature: {β¦Featureβ¦}} β renderer applies live
{type:"wish_granted", wish_id, epitaph, epoch}
{type:"wish_rejected", wish_id, reason}
{type:"heartbeat"} β every 15s
Set X-Accel-Buffering: no on the SSE response (proven necessary on Spaces β see glassblower).
HTTP API (app.py, AGENT B)
GET /api/state β {world: {version, epoch, features:[...]}, queue: {...}, wishes_recent:[...]}
POST /api/wish {text} β {wish_id, position} (400 w/ poetic reason if moderation fast-path rejects)
GET /api/stream β SSE
GET /api/wishes β [{wish_id, text, epitaph, epoch, ts}] (Genesis Log index)
GET /api/wishes/{id} β full WishTrace (for deterministic replay)
GET / β web/index.html (StaticFiles)
GET /book β web/book.html
/panel β minimal gr.Blocks mounted via mount_gradio_app (satisfies "Gradio app" rule:
altar console β submit a wish, view raw world JSON, link to traces dataset)
app.py must work under plain python app.py (uvicorn.run, port = $PORT or 7860) β HF sdk:gradio
runs the script directly. ZeroGPU REQUIRES sdk:gradio, so make this work; Dockerfile.fallback is
break-glass only.
WishTrace (persisted, one JSONL line per granted wish β traces/wishes.jsonl)
{"wish_id":"w_000005","text":"...","submitted_at":0,"moderation":{"allowed":true,"category":null},
"reading":"...","turns":[{"thought":"...","call":{...}|null,"observation":"..."}],
"epitaph":"...","feature_ids":["f_000017"],"model":"...","backend":"llamacpp","ms_total":48211}
Persistence (server/persistence.py, AGENT B): rebuild world from JSONL on boot (genesis + every
trace's features). After each granted wish: append JSONL; push traces/wishes.jsonl to an HF
dataset repo (HF_TOKEN + GODSEED_DATASET envs; skip silently if unset β local dev). The dataset
IS the persistence across Space restarts (download on boot if local file missing) AND the Sharing
is Caring badge AND Best Agent evidence.
Renderer (web/, AGENT D β the WOW is here; budget most effort)
Three.js (vendor from glassblower web/lib). Composition:
- Planet: icosphere (subdiv ~6), vertex displacement = sum of feature gaussians (raise/lower)
modulated by seeded noise Γ roughness. On
world_delta, lerp the displacement in over ~2s (terrain visibly rises). Obsidian-dark base material, biome tinting near flora. - Flora: InstancedMesh per kind, emissive, seeded scatter within radius_deg, scale-in animation staggered by seeded delay. Glowgrass = shader points; trees/mushrooms = low-poly kit.
- Water: TubeGeometry along great-circle spline through waypoints, emissive glow (low transmission + emissive β glass learnings), gentle flow shader. Pools = glowing discs w/ ripple.
- Structures: small low-poly procedural kit (lighthouse with rotating beam, monolith, shrine, village cluster w/ lit windows, beacon, arch), emissive accents.
- Weather: GPU particles (rain streaks / snow / embers / mist planes / storm = rain+flashes).
- Sky: palette-driven gradient + stars (Points, density param) + 0..3 moons + aurora bands
(palette
aurora). Background environment affects planet lighting tint. - Inscriptions:
orbit= glowing text ring slowly orbiting (canvas texture on curved plane);stone= text plaque at lat/lon. - Bloom: UnrealBloomPass, selective, threshold β0.66. Cap pixelRatio β€2. Must hold ~60fps on a laptop, degrade gracefully on phones (reduce instances/subdiv).
- The god's gaze: on
tool_call, camera eases to the target lat/lon, then resumes slow auto-orbit. This is the demo money-shot. - Sim/replay core: fixed-step
tick()/seek(t)decoupled from rAF (headless-safe, makes Genesis Log replay + demo capture free).
UI (index.html): full-bleed canvas. Wordmark "GODSEED" (letterspaced display serif β e.g. Cormorant Garamond via Google Fonts), thin HUD: wish input ("make a wish"), queue chip ("3rd in line Β· the god grants one wish at a time"), thought ticker (mono font, streaming), epoch counter ("Epoch 17 Β· 23 wishes granted"). Deep-space black, gold/violet accents. NO generic AI-gradient-purple-on-dark-card look β aim for liturgical-modern, like a Kinfolk issue about a small god. Footer: "Genesis Log" link.
book.html (Genesis Log): list of granted wishes (epitaphs); click one β replay THAT wish: render
world at features[0..K), then animate wish K's deltas with its recorded thoughts replayed in the
ticker. Pure client-side from /api/wishes/{id}. Zero GPU. Shareable URL #w_000005.
web/mock/ : a static mock world JSON (genesis + ~10 varied wishes exercising ALL 8 tools) + a
scripted SSE-like event feed (JS array) so the renderer is fully developable + screenshottable with
NO backend: python3 -m http.server 8123 --directory web + ?mock=1.
AGENT D self-verifies: adapt glassblower tools/shot.mjs, screenshot at multiple sim times,
LOOK at the PNGs, iterate until genuinely beautiful. Don't ship the first thing that renders.
Local dev
- Python 3.12 venv via uv (
uv venv -p 3.12 .venv && uv pip install -r requirements.txt). System 3.14 is too new for the ML stack. GODSEED_BACKEND=mock PORT=7891 .venv/bin/python app.py- requirements.txt: keep base CPU-light (fastapi, uvicorn, gradio, pydantic, huggingface_hub, llama-cpp-python). torch/transformers/spaces go in a clearly-marked ZeroGPU block (commented or extras) until the benchmark decision.
City Update (v1.1 contract β June 12 PM)
Player-requested ("building games": cafeterias, big buildings, warehouses, cars). Three additions, same diorama soul. Backwards compatible: old features render unchanged; additions are additive enums + ONE new tool (copy that says "exactly 8 tools" must be updated to 9 everywhere: README, ARCHITECTURE intro, prompts).
New structure kinds (place_structure enum +=
tower,warehouse,cafe):towerβ tall slender multi-tier block, dense lit windows, slow-pulsing rooftop light. The "big building".warehouseβ long low gabled hall, one big glowing door, sparse windows.cafeβ small warm box: awning plane, spill of warm light on the ground, 2-3 tiny table dots outside. Hue tints the glow. All three: low-poly procedural kit pieces matching existing style (emissive accents, seeded variation), instanced where possible.
New tool #9
spawn_lifeβ moving inhabitants:{lat, lon, radius_deg 1..20, kind: carts|birds|fireflies, count 1..12, hue 0..360}cartsβ tiny lantern-cart sprites that GLIDE along the nearest stream path within radius (fallback: a seeded loop around the anchor). Distant traffic at dusk. Speed slow, constant, sim-time driven.birdsβ a small flock circuiting above the terrain at low altitude, seeded loop, slight bob.firefliesβ drifting glow points inside the radius, near the ground. Renderer: newweb/planet/life.js, instanced, deterministic seeded paths driven by tick(simTime) (replay-safe, headless-safe). Engine: spec + clamps in tools.py; features append-only as usual. GBNF grammar + mock scripts + tool docs must all gain the tool (docs auto-render from as_dict β).
Cinematic descent ("visit it"):
rig.descend(targetDir, {duration})β swoop from orbit to ~1.06R above ground (clears terrain via the analytic height fn), slow 20-30Β° glide arc over the target with gentle look-ahead, then ease back to orbit. Fully sim-time deterministic.- Triggers: a "descend" link on the epitaph card after a wish is granted (targets the wish's last landed feature), and on Genesis Log replays after the final delta. ESC / click cancels. No free controls, no collision β it's camera liturgy, not an FPS.
Build ownership when this ships: (A) engine/tools.py + mind/grammar.gbnf + mind/mock_scripts.py + tests; (B) web/planet/structures.js (new kinds only); (C) web/planet/life.js + web/planet/camera.js + main.js/book.js descend hooks. Copy updates (README 8β9 tools etc.) ride with (A).
Town Mode (v1.2 contract β June 12 PM, "Town on the planet")
User feedback: a city wish produced one tower on the far side of a planet-sized sphere β reads empty. The fix is a deliberate experience shift: the DEFAULT view is a town you build up close (SimCity feel); the full planet becomes the dramatic zoom-out reveal. Append-only world preserved; genesis UNCHANGED (the live shared world must keep rebuilding identically). All additive.
The town anchor (engine + renderer compute IDENTICALLY)
townCenter(world) = the seeded-weighted centroid (unit-vector mean, renormalized) of all
place_structure + build_district feature directions, EXCLUDING genesis. Fallback when none exist:
the genesis monolith at lat 14, lon 38. Engine exposes it in the world summary; the renderer uses it
for the default camera. A town gets a deterministic name from crc32(round(lat),round(lon)) β a small
curated name list (e.g. "Lowmere", "Ashford", "Tessen") so the summary + HUD can say "the town of X".
Density comes from each tool call, not from many (the 9B reliably plans only ~2-3 calls)
New tools (now 11 β update every "9 tools" copy β 11; list build_district + place_road):
| tool | args |
|---|---|
build_district |
lat,lon,radius_deg 2..15, density 0..1, hue 0..360 β renderer places a SEEDED neighborhood: a cluster of small houses on a rough grid, footpath/road connectors between them, and 1 occasional civic building. ONE successful call = a visible block. This is the SimCity unlock. |
place_road |
path [[lat,lon] Γ2..6] β a paved, faintly-lit road spline laid ON the surface; visually DISTINCT from place_water glowing streams (warm stone/amber, matte, dashed centerline feel β not emissive cyan). |
place_structure.kind enum += bank, market, house (single landmark homes/civic buildings; the
existing low-poly kit conventions). Full set: lighthouse|monolith|shrine|village|beacon|arch|tower|
warehouse|cafe|bank|market|house.
Steering the god to GROW THE TOWN (mind/prompts.py + engine/summary.py)
- summary.py: name the town + its center + building count ("The town of Lowmere stands near (14,38):
3 towers, a cafΓ©, 12 houses."). When the wish asks for buildings/a city, the god should ADD to the
existing town, not scatter β build near townCenter, connect with
place_road, and reach forbuild_districtfor neighborhoods. Persona gains: "You are growing one town. New buildings rise beside the old ones, linked by roads β never alone in the wilderness." - This is steering, not enforcement (keeps the "god decides" purity). The camera following density means even a stray build is visible; over wishes the town concentrates.
Camera = two modes (web/planet/camera.js + main.js)
- TOWN view (DEFAULT on load): camera sits LOW and close, framing a ~28Β° cap around townCenter β buildings read large, like standing over a model town. This is what visitors see first now (not the full orbit).
- WORLD view (the reveal): a HUD control "behold the world β" eases out to the full-planet orbit (today's gorgeous wide shot) and back. The demo money-move: build the town, then pull back to show it's one patch on a shared planet.
- On each
world_delta/grant, frame the new feature WITHIN the town zoom (don't fly to the far limb). - The existing descent stays (epitaph card) β now it descends within the town.
Tame the god-needle
The orbital "god instrument" needle currently dominates the frame (huge gold double-cone). In TOWN view it must be small/high or hidden; show it prominently only during active granting (it "writes" the wish) and in WORLD view. Scale it down ~60% at rest.
Ownership for the Town Mode build
- ENGINE+MIND (A): engine/tools.py (build_district, place_road, +3 structure kinds), engine/summary.py (town name+center+counts), engine/world.py (_observation for new tools), mind/grammar.gbnf, mind/mock_scripts.py (town-growth scripts), mind/prompts.py (grow-the-town steering + 11-tool copy), tests; README/ARCHITECTURE 9β11 copy.
- RENDERER (B): web/planet/structures.js (bank/market/house kit), web/planet/district.js (NEW β seeded house+road neighborhood), web/planet/roads.js (NEW β paved road splines) OR fold roads into water.js styling, web/planet/world.js wiring, needle scale-down (find it β likely sky.js or scene.js).
- CAMERA+HUD (C): web/planet/camera.js (TOWN/WORLD modes + townCenter framing), web/main.js + book.js (default TOWN view, "behold the world" toggle, frame-within-town on delta), web/index.html + style.css (the toggle control). townCenter helper shared via web/planet/util.js.
Deploy plan (not in this build phase β for context)
- Personal benchmark Space first: llamacpp 4B on free CPU + (separately) ZeroGPU 30B-A3B; measure tok/s before committing the headline backend.
- Org Space
build-small-hackathon/godseed, sdk:gradio. README YAML: full track + sponsor + badge tags (copy exact tag strings from case0/her READMEs β AGENT B: fetchhttps://huggingface.co/spaces/build-small-hackathon/case0/raw/main/README.mdand mirror tag style). - v0 ships TONIGHT (June 12) on llamacpp 4B. Social + like-farming starts immediately.