build-small-hackathon/hackathon-advisor
16
1# Build Small Hackathon Advisor — Design & Implementation Notes2 3> A **small-model agent** with text and voice input that investigates what other people have already built4> for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon) and brainstorms an original new design5> *with you*. Output = streaming text + live visuals (no TTS). All models small, open-weight, run locally.6>7> The literal "advisor" is the **engine**; the user-facing experience is **The Unwritten Almanac** — Mothback, an8> owl-moth archivist, keeps the Wood's book of fates and divines you a still-unwritten project page (ink **bleeds +9> cites real Spaces** if you overlap, **blooms gold** if it's new). This project is itself a Build Small submission10> (hack window 2026-06-05 → 2026-06-15).11 12---13 14## 1. Locked decisions & review corrections (2026-06-07)15 16A multi-agent adversarial review (5 dimensions, web-verified) set the direction below. **This section is the17authoritative decision log; the rest of the doc is written to be consistent with it.**18 19**Locked decisions (Jacob):**201. **Concept = The Unwritten Almanac** (chosen 2026-06-07 from a 12-concept brainstorm). Mothback the owl-moth21 archivist divines a fate-page; ink **bleeds and cites the real Spaces** you overlap (page 47, page 112…), or22 **blooms gold + sprouts a leaf** when it's unwritten. Engine unchanged underneath (crawl → whitespace/originality →23 score). The dry "advisor" stays under the hood. Full spec + de-risking grafts in §2.242. **Text-first with voice input.** The core workflow remains typed/editable text. Voice records or uploads a note,25 transcribes it with batch ASR, and places the transcript in the same idea box. Real-time streaming + in-browser turn26 detection are **deferred**.273. **Add a 🎯 Well-Tuned fine-tune** — a small LoRA (MiniCPM5 advisor persona / tool-calling), trained on Modal,28 published to the Hub → 6/6 badges → strong shot at 🎖️ Bonus Quest Champion ($2,000).294. **ASR = Nemotron batch.** `nvidia/nemotron-speech-streaming-en-0.6b` runs through NVIDIA NeMo in a ZeroGPU function.30 Audio is normalized to mono WAV before calling `transcribe([wav])`.31 32**Verified corrections:**33- **Drop SGLang.** It needs a persistent GPU process → incompatible with ZeroGPU (same root cause as vLLM). Run34 MiniCPM5 via plain `transformers` inside `@spaces.GPU` and parse its XML tool calls in our own code.35- **gr.Server custom UI streaming IS shipped** (the launch blog only deferred the *explanation*). The deployed browser36 UI calls our own same-origin `/api/agent-turn` NDJSON stream with `fetch`; `_engine_turn` itself is wrapped in37 `@spaces.GPU`, so the real MiniCPM5 + LoRA path still runs on ZeroGPU. The `@app.api("/agent_turn")` generator stays38 available for Gradio/Python clients and contract checks, but the visible app no longer depends on the CDN39 `@gradio/client` path after real Space testing showed that browser turn could hang while the backend completed.40- **OpenAI Track has NO model requirement** ("OpenAI's own podium across all submissions") → auto-entered; a free41 lottery ticket. Do NOT add gpt-oss (breaks Tiny Titan, dilutes the small-model thesis). Deliberate non-target.42- **Badges = 6 total** (Tiny Titan is a $1.5k *special award*, not a badge). Decision #3 takes us from 5/6 → 6/6.43- **Tiny Titan** = "best ≤4B model"; our largest single model is MiniCPM5 (1.08B), total stack ~1.9B → eligible.44 45**New build requirements surfaced by the review (designed into the sections below):**46- **Jargon alias layer (§7):** a 0.6B ASR mistranscribes our own vocab (Nemotron, MiniCPM5, EmbeddingGemma, ZeroGPU…).47 Deterministic code-side fuzzy/alias map over our small CLOSED vocab, applied before any tool call and before display.48 Surface "heard: neutron → Nemotron" as a delightful trust moment. (Active once voice is added.)49- **Tool-call degradation ladder (§8):** the 1B brain WILL emit broken tool calls (MiniCPM5-1B has a documented50 "broken tool calling" report). Wrap parse in try/except, retry once at low temp, validate name+args vs JSON-Schema in51 code (reject-and-repair), canned lines for empty results, a token **watchdog** that shows "trying again" instead of52 dead air (the screen is the only feedback channel — no TTS).53- **Latency / optimistic UI (§9/§11):** ZeroGPU cold start + 1B generation = seconds of potential dead air. Optimistic54 UI on submit, pre-animate the project wall, set a latency budget. (The torch.compile cold-start penalty does NOT55 apply — we don't use it.)56 57**Day-1 go/no-go spikes (before any feature work):**58- Trivial `@spaces.GPU` hello-cuda build GREEN on torch 2.8+, deps pinned, heavy deps added one at a time.59- `gr.Server` minimal: static `index.html` + one same-origin `/api/agent-turn` NDJSON stream, plus the retained60 `@app.api()` generator for external clients, on the real ZeroGPU Space.61- Nemotron `nemo_toolkit[asr]` install + one batch `transcribe()` inside `@spaces.GPU` (decision #4).62 63---64 65## 2. Concept — The Unwritten Almanac (text-first)66 67The engine, regardless of skin:68 691. **Investigate** the `build-small-hackathon` HF org — what Spaces exist, which models, what's saturated, and where70 the **whitespace** is — using a local EmbeddingGemma index.712. **Brainstorm** with the user: propose ideas, **score** them against a fixed rubric (originality vs. existing72 projects, delight, AI-necessity, feasibility, param budget, prize-fit), and maintain an **idea board**.733. **Respond** as streaming text + live visuals in a custom `gr.Server` frontend (no TTS — the visual is the "voice").74 75**The skin (chosen): The Unwritten Almanac.** **Mothback**, a dusty owl-moth archivist, keeps the Wood's *book of76fates*. Every project already built in the org is an inked page; she divines you a destined entry on a still-blank page,77the ink writing itself live.78 79**The two-beat wow (this IS the engine, rendered):**80- You type one line about yourself / your idea. Inked pages riffle past (each = a real crawled Space).81- **Bleed:** if your idea overlaps existing work, the ink **seeps blood-red** and cites the exact real Spaces — "the82 Wood already wrote this, on page 47 and page 112" (= `get_project` overlap on the top retrieval hits). The burn is83 **factual**, so it can't fall flat the way a 1B's invented joke can.84- **Bloom:** you say "write bolder"; the next entry flows **gold**, a green leaf sprouts — "this page has never been85 inked" (= a `find_whitespace` gold candidate).86- A **wax seal** presses in, lighting five quadrants as the idea qualifies (= `score_idea`: Originality, Delight,87 AI-Necessity, Feasibility, Prize-Fit).88 89**Engine ↔ skin mapping:** `search_projects`/`get_project` overlap → the bleed + citations; `find_whitespace` → the90blank/gold pages; `score_idea` → the wax-seal quadrants; `save_idea` → the written fate-page; agent persona =91**Mothback** (Layer A system prompt + the 🎯 Well-Tuned LoRA = her voice).92 93**Shareable artifact (Community Choice):** the page exports as a PNG that looks **torn from an ancient grimoire** —94aged parchment, a coined fate-name as title, the self-written prophecy, the five-quadrant seal, and a verdict stamp95(**"UNWRITTEN · 0 echoes"** vs **"ECHO ×3"**). Built-in caption: "Mothback inked my fate page for #BuildSmall —96UNWRITTEN." People compile draws into a "chapter" and dare friends to get a page that doesn't bleed.97 98**Grafted de-risking (from runner-up concepts):**99- **Tone = dry-but-benevolent** (Roastleaf's whiplash): the bleed-citation gently stings, the gold-bloom is sincerely100 delighted; the burn is true-by-construction (real cited Spaces).101- **Templated structure (key risk-killer):** bank entry/roast templates (citation + dry verdict + redemptive branch);102 the 1B only fills in real Space titles + the idea — **never improvises whole comedy**.103- **Latin-binomial fate-names** (e.g. "Ludus Vocalis Infantium") via templated scaffolds — built-in wit, backstops a104 1B that might produce corny names.105- **"You vs the Wood" margin glyph:** a tiny cluster-dot thumbnail on the page showing your gold page among the inked106 crowd — cheap SVG, visual PROOF the gap is real.107- **Thin-org mitigation (load-bearing):** precompute whitespace clusters at Modal build-time and pin several DISTINCT108 blank-page candidates so "write bolder" always lands on a real, varied gap (the org may be only ~30–60 Spaces). Tune109 the echo threshold toward *more frequent bleed* so the demo always has its "low" before the "wow".110 111**Defaults (revisit if time):** single-page artifact first (chapter compiler later); page-numbers visible, real titles112on hover (keep the burn aimed at the idea, not a named builder); seal animation = safe typewriter + static-stamp floor113first, bespoke ink-reveal last. Voice input is batch ASR that fills the same idea box before the user presses Ink.114 115Input is **text-first**; the experience is fully delightful with typed input alone.116 117AI is genuinely **load-bearing**: embeddings power the whitespace/originality analysis and the LLM drives the118investigate → ideate → score loop — the experience collapses without the models (supports 🤖 Best Agent + TTW119"AI necessity").120 121---122 123## 3. Model stack (confirmed exact repo IDs)124 125| Role | Model | Params | Runtime | License | Prize hook |126|---|---|---|---|---|---|127| STT (batch voice input) | **`nvidia/nemotron-speech-streaming-en-0.6b`** | 0.6B | NeMo, GPU+CUDA | NVIDIA Open Model (commercial OK) | 🟩 NVIDIA Nemotron Quest |128| LLM brain | **`openbmb/MiniCPM5-1B`** ("OpenCPM5") | 1.08B | **transformers** (self-parse XML) / llama.cpp | **Apache-2.0** | 🏮 OpenBMB |129| Embedder | **`ggml-org/embeddinggemma-300m-qat-q8_0-GGUF`** | ~300M | llama.cpp / llama-cpp-python | Gemma | 🔌 Off the Grid · 🦙 Llama Champion · 🟢 Modal |130| Fine-tune | LoRA on MiniCPM5 → published to Hub | — | PEFT / HF Jobs | — | 🎯 Well-Tuned |131 132**Total ≈ 1.98B params → ≤4B → 🐜 Tiny Titan eligible.** All open-weight, all runnable locally → 🔌 Off the Grid.133 134> Naming: "OpenCPM5 1B" = `openbmb/MiniCPM5-1B` (MiniCPM 5.0, ~May 2026). "EmbeddingGemma 270M" =135> `google/embeddinggemma-300m` (308M total; 270M = non-embedding transformer params). **SGLang dropped** (ZeroGPU136> incompatible). STT is used in **batch voice-note** mode, not a persistent stream.137 138---139 140## 4. Deployment & architecture (single path)141 142With **text-first + batch ASR**, the old "streaming ASR vs ZeroGPU" Config A/B tension dissolves — there is one path:143 144- **ZeroGPU Gradio-SDK Space** (free). GPU is attached only inside `@spaces.GPU` calls (default 60s, max ~120s,145 RTX Pro 6000 Blackwell, `large`=48 GB). Per-turn inference fits this model exactly.146- **Text-first runtime loop:** user types → custom `/api/agent-turn` NDJSON endpoint → one `@spaces.GPU` call runs147 MiniCPM5 (tool loop, in `transformers`) → streamed text tokens + live visual updates. The `@app.api()` endpoint148 remains as the Gradio-client contract for external checks.149- **Voice input:** push-to-talk records an utterance or uploads a voice note → `/api/transcribe` normalizes audio with150 ffmpeg → one `@spaces.GPU` call runs Nemotron ASR through NeMo → transcript fills the idea box. No persistent stream,151 no WebRTC, **no TURN server**.152- **Modal (build-time only):** crawl the org + build the llama.cpp EmbeddingGemma vector index offline; the Space ships153 with checked-in project vectors. Runtime never calls Modal → 🔌 Off the Grid holds (see §10).154 155> Off the Grid = no proprietary cloud inference APIs. Open weights on an HF GPU Space / local box / Modal all qualify.156 157**Deferred:** real-time streaming ASR and turn detection are not part of the shipped app.158 159---160 161## 5. Per-model implementation notes162 163### 5.1 ASR — `nvidia/nemotron-speech-streaming-en-0.6b` (batch)164 165- **Primary, batch usage (simple):**166 ```python167 import nemo.collections.asr as nemo_asr168 asr = nemo_asr.models.ASRModel.from_pretrained("nvidia/nemotron-speech-streaming-en-0.6b")169 text = asr.transcribe(["utterance.wav"]) # 16 kHz mono WAV in; punctuated EN text out170 ```171 Runtime install: `packages.txt` provides `ffmpeg` and `libsndfile1`; `requirements.txt` pins172 `nemo_toolkit[asr]==2.7.3` plus Cython and packaging. The app records or uploads audio, normalizes it to mono173 16 kHz WAV, runs NeMo in a ZeroGPU function, then returns the transcript to the idea box. Hosted NVIDIA NIM API would174 break Off the Grid, so it is not used.175 176### 5.2 MiniCPM5-1B brain — `openbmb/MiniCPM5-1B` (transformers, self-parsed XML)177 178- Context 128K, bilingual (EN/ZH), Apache-2.0. `enable_thinking=False`, `temperature=0.7, top_p=0.95` for fast tool calls.179 ```python180 from transformers import AutoModelForCausalLM, AutoTokenizer181 tok = AutoTokenizer.from_pretrained("openbmb/MiniCPM5-1B")182 model = AutoModelForCausalLM.from_pretrained("openbmb/MiniCPM5-1B", torch_dtype="auto", device_map="auto")183 inputs = tok.apply_chat_template(messages, tools=TOOLS, add_generation_prompt=True, enable_thinking=False,184 tokenize=True, return_dict=True, return_tensors="pt").to(model.device)185 ```186- **Tool calling:** pass JSON-Schema tools via the chat template `tools=` arg; the model emits **XML**187 `<function name="get_weather">{"city":"New York"}</function>`. **Parse this ourselves** (SGLang dropped). Wrap parse188 in try/except and validate against the schema — see the degradation ladder (§8).189- **Local / CPU & llama.cpp (Off the Grid · Llama Champion):** `openbmb/MiniCPM5-1B-GGUF:Q4_K_M` (688 MB) via llama.cpp190 or Ollama (CPU-viable). fp16 ≈ 3–4 GB VRAM. `openbmb/MiniCPM5-1B-MLX` for Apple Silicon. (llama.cpp MiniCPM5191 tool-calling is a pending PR — verify before relying on it for the badge runtime.)192- **1B discipline:** small tool schemas, few params each, clear descriptions, low temp, single-hop tool calls.193 194### 5.4 EmbeddingGemma GGUF — `ggml-org/embeddinggemma-300m-qat-q8_0-GGUF`195 196- Active retrieval model: `embeddinggemma-300m-qat-Q8_0.gguf`, 768-dimensional normalized embeddings.197- Build-time path: Modal remote function runs `llama-cpp-python` with mean pooling and writes `data/project_index.json`.198- Runtime path: Space embeds each user query through the same GGUF model via llama.cpp, then performs local cosine search199 over checked-in project vectors.200- Evidence is recorded in index metadata: model repo, GGUF filename, runtime, dimensions, build source, builder script,201 llama-cpp-python version, and Modal app name.202 203### 5.5 llama.cpp support (🦙 Llama Champion)204 205The active Llama Champion path is the retrieval model: the project index is built with EmbeddingGemma GGUF through206llama.cpp on Modal, and runtime query embeddings use the same llama.cpp path.207 208| Model | llama.cpp? | Runtime | Notes |209|---|---|---|---|210| `openbmb/MiniCPM5-1B` | ✅ planned only | llama.cpp / Ollama | Not used for deployed tool-calling; Transformers + LoRA is the deployed brain. |211| `ggml-org/embeddinggemma-300m-qat-q8_0-GGUF` | ✅ active | llama.cpp / llama-cpp-python | Builds project vectors on Modal and embeds runtime queries in the Space. |212| ASR (Nemotron) | ❌ | NeMo | FastConformer-RNNT |213 214The checked-in index and runtime query embedder must stay on the same GGUF file.215 216---217 218## 6. Agent context design (built for a 1B brain)219 220Core principle: **the 1B model is a router + arg-filler. All heavy work (crawl, summarize, score, rank, dedup) lives in221code.** Keep live context to ~800–1200 tokens of *curated* view, never raw data.222 223- **Layer A — System (static, ~250 tok):** identity/character; hackathon hard rules (≤32B, Gradio Space, demo video) so224 it self-filters infeasible ideas; targeted prizes (biases ideation); reply style (short, one question at a time);225 explicit tool-use instructions + the canonical jargon vocabulary (so it can self-correct, §7).226- **Layer B — Session state (re-rendered each turn by code, ~300 tok):** user profile; locked decisions (track, side227 quests, models); **idea board** (2–3 candidates, one line + scores); compact "projects already seen" summary.228- **Layer C — Ephemeral (~300 tok):** last 2–3 turns; the most recent tool result as a **refined card** (not raw JSON).229 230---231 232## 7. Agent tool design233 234Few tools, few params each, short descriptions (1B-friendly). Heavy logic in code.235 236**Jargon alias layer (input normalization).** Before any tool call and before display, run ASR/user text through a237deterministic fuzzy/alias map over our small CLOSED vocab (model names and goal names) — e.g. RapidFuzz238`token_set_ratio` / double-metaphone — mapping "neutron"/"nemo tron" → Nemotron, "mini cpm" → MiniCPM5, "zero gpu" →239ZeroGPU. Surface the correction ("heard: neutron → Nemotron") as a trust-building, slightly delightful moment.240 241**Research — investigate existing projects (the core value).** Data = `build-small-hackathon` org Spaces, pre-crawled242into a local snapshot + EmbeddingGemma index (keeps Off the Grid at runtime).243 244| Tool | Signature | Returns (refined) | Heavy work |245|---|---|---|---|246| `list_projects` | `(track?, sort?)` | top-N project cards | HF Hub API + summarize |247| `search_projects` | `(query)` | top 5 cards | EmbeddingGemma retrieval |248| `get_project` | `(id)` | card + overlap-vs-board verdict | code computes overlap |249| `find_whitespace` | `()` | under-explored niches | cluster the index, find gaps |250 251`find_whitespace` is the originality engine (TTW judges originality) — it names where nobody has built yet.252 253**Ideation / state.**254 255| Tool | Signature | Purpose |256|---|---|---|257| `save_idea` | `(title, pitch)` | add/update a candidate on the idea board |258| `score_idea` | `(id)` | fixed (hardcoded) rubric → scores + gaps; the 1B only triggers + verbalizes |259| `compare_ideas` | `()` | rank the board, articulate tradeoffs |260| `make_plan` | `(id)` | build plan + goals the current direction can support |261| `update_profile` | `(field, value)` | record skills/time/prefs → Layer B |262| `set_goals` | `(goals[])` | change selected goals → updates Layer A bias |263 264---265 266## 8. Agent loop (single-hop + degradation ladder)267 268```269on user input (text; or voice → batch ASR → text):270 normalize via jargon alias layer271 ctx = LayerA + render_state(LayerB) + last_turns + last_tool_card272 out = MiniCPM5(ctx, tools=TOOLS, enable_thinking=False, temp=0.7) # → tool_call | reply273 try: parse XML tool call274 except / invalid name|args (vs JSON-Schema): # degradation ladder275 retry once (temp≈0.3, "emit ONLY one valid tool call")276 still bad → run a safe default tool (find_whitespace) so the screen never freezes277 if tool_call: card = run_tool(out); reply = MiniCPM5(ctx + card) # single follow-up, no long ReAct278 empty/zero result → canned advisor line (never say nothing)279 stream reply tokens → custom UI | token watchdog: no token in N s → "trying again" visual (not dead air)280 update_state(LayerB)281```282 283**Max one tool-call then reply.** A 1B can't sustain multi-step ReAct; wrap multi-step flows (`search → get_project →284score`) into one *code* "research" action the model calls once. The degradation ladder is a **first-class UX surface**285(§11), not an error branch — the screen is the only feedback channel (no TTS).286 287---288 289## 9. ZeroGPU deployment notes290 291- `import spaces; @spaces.GPU(duration=…)`. GPU only inside decorated fns; **Gradio-SDK Space only** (no Docker ZeroGPU).292- Load models at **module level**, `.to('cuda')` once (emulated until first real GPU call); real compute inside the293 decorator. torch 2.8+; **no `torch.compile`** (use AOT). Quota PRO ~40 min/day → never idle-hold the GPU.294- **Frontend → backend via same-origin `fetch("/api/agent-turn")`** reading NDJSON from our FastAPI route. The GPU295 boundary is `_engine_turn`, decorated with `@spaces.GPU`; `@app.api()` endpoints remain available for Gradio-client296 tests and external callers.297- All four models fit in `large` (48 GB). Keep each `@spaces.GPU` call short for queue priority.298 299---300 301## 10. Modal — offline pipeline (build-time only → preserves Off the Grid)302 303Modal = build-time; runtime never calls it. This is how the app claims **both** 🟢 Modal and 🔌 Off the Grid. The304canonical command is:305 306```bash307.venv/bin/modal run scripts/modal_build_project_index.py \308 --projects data/projects.json \309 --out data/project_index.json310```311 312The remote function installs `llama-cpp-python`, downloads313`ggml-org/embeddinggemma-300m-qat-q8_0-GGUF/embeddinggemma-300m-qat-Q8_0.gguf`, embeds every project card through314llama.cpp, and returns a schema-v2 JSON index. The local entrypoint writes that payload into the repo for Space runtime.315 316Latest successful run: `hackathon-advisor-llama-index` on Modal, producing a 100-document, 768-dimensional normalized317index at `2026-06-07T08:16:19+00:00`.318 319---320 321## 11. Frontend — `gr.Server` custom UI (🎨 Off-Brand)322 323No TTS → the **visual output is the agent's "voice"**; it must carry the delight (this is what earns Off-Brand, and the324TTW polish + Best Demo score). The visual world is **The Unwritten Almanac** (§2): a candlelit tree-hollow with a heavy325open grimoire as the hero component.326 327- `gradio.Server` is a FastAPI subclass serving **your own frontend** while still exposing `@app.api(name=...)`328 functions for Gradio/Python clients. The visible app uses first-party `@app.post()` endpoints for deterministic329 browser behavior; the GPU boundary stays in the decorated engine function.330 ```python331 from gradio import Server332 from fastapi.responses import HTMLResponse333 app = Server()334 335 @app.api(name="agent_turn", concurrency_limit=2)336 async def agent_turn(message: str):337 for token in run_agent_stream(message): # generator → SSE338 yield token339 340 @app.get("/", response_class=HTMLResponse) # custom UI replaces Gradio's default page341 async def home(): return open("index.html").read()342 app.launch()343 ```344- Frontend calls via `fetch("/api/agent-turn")`, parses newline-delimited JSON events, and updates the grimoire as345 `start` / `token` / `done` messages arrive. Notes and chapter exports use `/api/field-notes` and `/api/chapter`.346- **UI surfaces (the grimoire is the canvas):** streaming reply = ink writing itself (typewriter on already-streaming347 tokens); `search_projects`/overlap → **bleed** animation + page-number citations (real titles on hover);348 `find_whitespace` → **gold bloom** + sprouting leaf + a one-shaft light-mask ("the page chooses you");349 `score_idea` → **wax-seal** five-quadrant stamp; the riffling inked pages (fast page-flip of real Spaces) double as350 the project-wall; export = the torn-grimoire PNG artifact (§2). Jargon-correction toasts (§7) read as Mothback's351 margin notes; optimistic-UI loading + watchdog states (§8) are her "the page is choosing its words…". Cheap SFX:352 page-flip, quill scratch, wax-seal thunk.353- **Build the animation floor first:** safe typewriter + static stamp ships first (graceful degradation — the judges354 credited this); upgrade the ink-bleed / gold-bloom / seal-press last.355- **Fallback:** the backend (`tools.py`/`agent.py`) is UI-agnostic — if gr.Server misbehaves, fall back to356 `gr.Blocks` + `gr.HTML`, losing only the $1500 Off-Brand badge, never the submission.357 358---359 360## 12. Prize mapping361 362| Target | How it's earned |363|---|---|364| 🍄 Thousand Token Wood | **The Unwritten Almanac** (§2) — the bleed-citation wow IS the engine rendered; AI load-bearing; original |365| 🐜 Tiny Titan (special, $1.5k) | total ~1.98B, every model ≤4B; largest single = MiniCPM5 1.08B |366| 🔌 Off the Grid (badge) | all open weights run locally; offline index; no cloud inference at runtime |367| 🎯 Well-Tuned (badge) | published LoRA fine-tune of MiniCPM5 on the Hub (§10) → **6/6 badges** |368| 🎨 Off-Brand (badge + $1.5k) | `gr.Server` custom UI is the agent's output surface |369| 🏮 OpenBMB ($10k) | brain = MiniCPM5-1B ("OpenBMB pick") |370| 🟩 NVIDIA Quest (2× RTX 5080) | ASR = Nemotron (§5.1) |371| 🦙 Llama Champion (badge) | EmbeddingGemma GGUF retrieval index and runtime query embeddings run through llama.cpp (§5.5) |372| 📡 Sharing is Caring (badge) | publish the agent's tool-call trace to the Hub |373| 📓 Field Notes (badge) | this DESIGN.md → a build blog post |374| 🎖️ Bonus Quest Champion ($2k) | 6/6 badges (needs the Well-Tuned fine-tune) |375| 🤖 Best Agent ($1k) | real multi-tool loop: investigate → ideate → score → plan |376| 🟢 Modal ($20k credits) | offline crawl+embed + LoRA training on Modal (build-time, separated from runtime) |377| 🎬 Best Demo ($1k) | the mandatory demo video, made to sing (shared artifact + wow beat) |378| 🌀 OpenAI ($10k) | auto-entered ("across all submissions"); free lottery ticket, not a target |379| ❤️ Community Choice ($2k) | shareable tweetable artifact from the experience |380 381**6 badges** = Off the Grid, Well-Tuned, Off-Brand, Llama Champion, Sharing is Caring, Field Notes. Awards stack across382categories. Single-winner awards (Tiny Titan, Best Agent, Off-Brand, Best Demo) are eligibility ≠ win — the shared383lever is §11 custom-UI polish.384 385---386 387## 13. Risks / open items388 3891. **Deployment smoke tests are mandatory:** ZeroGPU Space build, same-origin NDJSON browser streaming, and Nemotron390 batch ASR in `@spaces.GPU` must be verified after every runtime dependency change.3912. **EmbeddingGemma is gated** — accept Gemma terms + `HF_TOKEN` before any crawl/build.3923. **MiniCPM5 tool-call reliability at 1B** — covered by the degradation ladder (§8); validate name+args in code.3934. **Concept skin** — **chosen: The Unwritten Almanac** (§2). Make-or-break is the bleed/bloom hero animation; build the394 safe typewriter + static-stamp floor first (graceful degradation), upgrade ink last. Watch the thin-org echo395 threshold + the dry-but-benevolent tone (real cited Spaces, never punch at a named builder).3965. **Param-budget claim** — document the 1.98B total in the README/Space card for Tiny Titan judging.397 398---399 400## 14. Build order401 402**Text-first vertical slice first; voice input is now part of the app.** Always keep a demoable artifact.403 4040. **Day-1 spikes** (§1) — get the three go/no-go builds green.4051. **`crawler.py` + Modal index** — crawl the org, embed with EmbeddingGemma, build the local index. *You immediately406 see what everyone's building and where the whitespace is.*4072. **`tools.py`** — research + ideation tools + the hardcoded `score_idea` rubric + the jargon alias layer, over the index.4083. **`agent.py`** — 3-layer context + single-hop loop + degradation ladder, MiniCPM5 via `transformers` (self-parsed XML).4094. **`app.py`** — `gr.Server` custom frontend (idea board, project/whitespace wall, streaming text), called via410 first-party `/api/...` endpoints; concept skin applied.4115. **Well-Tuned LoRA** — small fine-tune on Modal → publish to Hub (→ 6/6 badges).4126. **Voice input** — push-to-talk record and voice-note upload through Nemotron batch ASR in `/api/transcribe`.4137. **Polish + submission** — demo video + social post (Best Demo / Community Choice), publish agent trace (📡),414 write up Field Notes (📓).415 416**Deferred:** real-time streaming ASR and turn detection. The shipped path stays batch audio → transcript → editable idea.417 418---419 420## 15. Sources421 422**Models:** [nemotron-speech-streaming-en-0.6b](https://huggingface.co/nvidia/nemotron-speech-streaming-en-0.6b) ·423[MiniCPM5-1B](https://huggingface.co/openbmb/MiniCPM5-1B) · [MiniCPM5-1B-GGUF](https://huggingface.co/openbmb/MiniCPM5-1B-GGUF) ·424[embeddinggemma-300m](https://huggingface.co/google/embeddinggemma-300m)425 426**Platforms:** [ZeroGPU docs](https://huggingface.co/docs/hub/spaces-zerogpu) ·427[Introducing gradio.Server](https://huggingface.co/blog/introducing-gradio-server) · [Gradio Server Mode guide](https://www.gradio.app/guides/server-mode) ·428[Modal GPU](https://modal.com/docs/guide/gpu) · [Modal model weights](https://modal.com/docs/guide/model-weights) · [Modal pricing](https://modal.com/pricing) ·429[Build Small Hackathon](https://huggingface.co/build-small-hackathon)430 431*Verify-before-ship: Nemotron-in-ZeroGPU after dependency changes; MiniCPM5 license on the live card; llama.cpp MiniCPM5432tool-calling remains planned only and is not used by the deployed brain.*433 