--- title: Unstuck emoji: ๐Ÿงฉ colorFrom: indigo colorTo: purple sdk: gradio sdk_version: "6.17.3" python_version: "3.12.12" app_file: app.py pinned: false short_description: "Tiny timed steps that learn your time-blindness" tags: - build-small-hackathon - backyard-ai - track:backyard - track:wood - achievement:offbrand - achievement:fieldnotes - achievement:sharing - achievement:offgrid - achievement:llama - achievement:welltuned - sponsor:openai - sponsor:openbmb - sponsor:nvidia - sponsor:modal - tiny-titan - tiny-model - llama-cpp - off-brand - field-notes - sharing-is-caring - codex - agent-trace - zerogpu - qwen - adhd - time-blindness - task-breakdown - calibration - privacy - small-models --- # Unstuck Unstuck turns one overwhelming task into tiny timed steps, then learns your personal time-blindness and recalibrates the estimates to you. Built for the HF Build Small Hackathon (Backyard AI track). Runs a โ‰ค4B model (`Qwen/Qwen3-4B-Instruct-2507`). **Your data stays yours.** Plans and calibration history live in your browser (localStorage), not on the server โ€” nothing is shared between users, and only the task text you submit ever reaches the model. Export/Import gives you the full round-trip. What it does beyond a breakdown bot: a built-in step timer (Start โ†’ Done measures for you), per-category calibration learned from your actual times with a visible "Your patterns" history, progressive reveal (only the next step is live โ€” no wall of steps), recursive "Still stuck?" re-breakdown, skip-without-polluting-the-data, plan persistence across reloads, and a markdown checklist export. One `generate()` seam serves eight interchangeable backends: ZeroGPU, HF serverless inference, Nebius Token Factory, a fully-offline local GGUF (`offgrid`), OpenBMB **MiniCPM** (`minicpm`) and NVIDIA **Nemotron** (`nemotron`), a **fine-tuned** Qwen2.5-0.5B we trained on Modal and published to the Hub (`finetuned`), and that fine-tune **served on a Modal web endpoint** (`modal`) โ€” each picked by one env var with no app changes. ZeroGPU also falls back ZeroGPU โ†’ HF serverless โ†’ local fine-tune, so a plan always returns even if GPU quota is exhausted. ## Demo & submission - ๐Ÿ“บ **Demo video:** [watch the ~90-second demo](https://huggingface.co/spaces/build-small-hackathon/unstuck/resolve/main/unstuck-demo.mp4) - ๐Ÿ“ฃ **Social post:** https://x.com/arty_able/status/2066306266843021603 - ๐Ÿงพ **Agent trace (open trace):** https://huggingface.co/datasets/build-small-hackathon/unstuck-agent-trace - ๐Ÿ“ **Field notes (build write-up):** [HF blog post](https://huggingface.co/blog/art87able/building-unstuck-small) ยท [source](https://github.com/art87able/unstuck/blob/main/docs/field-notes.md) - ๐Ÿ’ป **Source:** https://github.com/art87able/unstuck **Model:** `Qwen/Qwen3-4B-Instruct-2507` (4B โ€” within the Tiny Titan โ‰ค4B bar). **Built small, in the open** with OpenAI Codex (Codex-attributed commits) and an honest deterministic calibration layer โ€” no AI in the differentiator. ## Badges & bonus quests โ€” the evidence | Badge / track | Claim | Evidence | |---|---|---| | ๐Ÿก **Backyard AI** (track) | A real anti-overwhelm tool for ADHD time-blindness | the whole app: tiny timed steps + honest per-category calibration | | ๐Ÿชถ **Tiny Titan** (โ‰ค4B) | Runs on a genuinely tiny model | default model `Qwen/Qwen3-4B-Instruct-2507` (4 B) | | ๐Ÿ”Œ **Off the Grid** (local-first) | No cloud APIs โ€” runs on the model in front of you | `UNSTUCK_BACKEND=offgrid` โ†’ local GGUF, zero network. **Verified:** [`docs/offgrid-proof.png`](docs/offgrid-proof.png) is a plan generated fully offline by the local model. See *Run fully offline* below. | | ๐Ÿฆ™ **Llama Champion** (llama.cpp) | Model runs through the llama.cpp runtime | the `offgrid` backend drives `Qwen3-4B-โ€ฆ-Q4_K_M.gguf` via `llama-cpp-python` (same proof screenshot) | | ๐Ÿงพ **Sharing is Caring** (open trace) | Agent trace shared on the Hub | [unstuck-agent-trace dataset](https://huggingface.co/datasets/build-small-hackathon/unstuck-agent-trace) | | ๐ŸŽจ **Off-Brand** (custom UI) | A frontend that pushes past the default Gradio look | custom `gr.themes` theme + a Fraunces gradient wordmark, gradient buttons, layered/hover step cards, indigo focus rings, fully de-branded chrome (see `THEME`/`CSS` in `app.py`) | | ๐Ÿ“ **Field Notes** | A published write-up of what we built and learned | [HF blog: *Building Unstuck small*](https://huggingface.co/blog/art87able/building-unstuck-small) (also in [`docs/field-notes.md`](https://github.com/art87able/unstuck/blob/main/docs/field-notes.md)) | | ๐Ÿค– **sponsor:openai** (Codex) | Codex-attributed commits in the repo | built with the OpenAI Codex CLI โ€” commit trail + the [agent-trace dataset](https://huggingface.co/datasets/build-small-hackathon/unstuck-agent-trace) | | ๐ŸŸข **sponsor:nvidia** (Nemotron) | The app runs on an NVIDIA Nemotron model | `nvidia/Nemotron-Mini-4B-Instruct` (4B, under the 32B cap) through the app's exact prompt + validator โ€” **verified 5/5 schema-valid** breakdowns ([`scripts/finetune/modal_nemotron_test.py`](https://github.com/art87able/unstuck/blob/main/scripts/finetune/modal_nemotron_test.py)). The larger reasoning `Nemotron-3-Nano-30B` is also callable via Nebius/NIM, but its think-tokens are less schema-reliable โ€” see the bake-off below | | ๐Ÿ”ต **sponsor:openbmb** (MiniCPM) | The app runs on an OpenBMB MiniCPM model | `UNSTUCK_BACKEND=minicpm` serves `openbmb/MiniCPM-V-4_5` over Nebius serverless via the same seam โ€” live-verified valid breakdowns | | โšก **sponsor:modal** (Modal) | Modal used to build **and serve** the app | the fine-tune was **LoRA-trained on a Modal A10G GPU** ([`modal_finetune.py`](https://github.com/art87able/unstuck/blob/main/scripts/finetune/modal_finetune.py)) **and is served on a Modal web endpoint** ([`modal_serve.py`](https://github.com/art87able/unstuck/blob/main/scripts/finetune/modal_serve.py)) reachable via `UNSTUCK_BACKEND=modal` โ€” development *and* runtime | | ๐ŸŽฏ **achievement:welltuned** (fine-tuned) | The app uses a fine-tuned model published on HF | [`art87able/unstuck-qwen2.5-0.5b-steps`](https://huggingface.co/art87able/unstuck-qwen2.5-0.5b-steps) โ€” Qwen2.5-0.5B LoRA-tuned on 130 distilled Unstuck breakdowns ([dataset](https://huggingface.co/datasets/art87able/unstuck-sft-breakdowns)); `UNSTUCK_BACKEND=finetuned` runs the app on it, and it's the always-on local fallback if ZeroGPU quota runs dry | | ๐Ÿ… **Bonus Quest Champion** | Most bonus criteria met | the twelve rows above, each genuinely earned | ## Backend bake-off โ€” the seam, measured Every small model is driven through Unstuck's *exact* breakdown contract (strict JSON schema + one repair retry) via the same `ModelAdapter` the app uses. Honest results ([`scripts/bakeoff.py`](https://github.com/art87able/unstuck/blob/main/scripts/bakeoff.py)): | Model (serverless on Nebius) | Valid / 5 | Avg steps | Avg latency | |---|---|---|---| | Qwen3-30B-A3B (teacher) | 5/5 | 5.0 | 2.9s | | OpenBMB MiniCPM-V-4.5 | 5/5 | 4.2 | **0.8s** | | NVIDIA Nemotron-3-Nano-30B (reasoning) | 0/5 | โ€” | 41.8s | | NVIDIA Nemotron-Mini-4B-Instruct *(on Modal)* | **5/5** | 5.4 | โ€” | | **Unstuck fine-tune** (Qwen2.5-0.5B) *(on Modal)* | โœ“ valid | โ€” | โ€” | The reasoning 30B Nemotron is the outlier โ€” its think-tokens overrun the token budget and break the schema, which is exactly why we use the 4B non-reasoning **Nemotron-Mini** for the NVIDIA path. ## Run locally ```bash pip install -r requirements.txt gradio UNSTUCK_BACKEND=hf_inference HF_TOKEN=... python app.py ``` The default backend is `zerogpu`, which the Space uses. The `hf_inference` path is the lightweight local option. ### Run fully offline (`offgrid`) No network, no cloud โ€” a local quantised GGUF drives the same `generate()` seam (the honest basis for the `offgrid` badge): ```bash pip install -r requirements.txt gradio llama-cpp-python # drop a Qwen3-4B GGUF (e.g. Qwen3-4B-Instruct-2507-Q4_K_M.gguf) into ./models/ UNSTUCK_BACKEND=offgrid OFFGRID_GGUF_PATH=models/Qwen3-4B-Instruct-2507-Q4_K_M.gguf python app.py ``` `llama-cpp-python` is deliberately left out of `requirements.txt` (it would bloat the Space build) โ€” install it only for offline use. Verified locally โ€” here it is generating a plan with **no network**, entirely on `Qwen3-4B-Instruct-2507-Q4_K_M.gguf` through llama.cpp: ![Unstuck running fully offline on a local GGUF via llama.cpp](docs/offgrid-proof.png) Reproducible transcript (env โ†’ local `.gguf` load โ†’ model output, no network): [`docs/offgrid-proof.log`](https://github.com/art87able/unstuck/blob/main/docs/offgrid-proof.log). ### Run on MiniCPM or Nemotron (Nebius serverless) The same `generate()` seam runs the app on OpenBMB MiniCPM or NVIDIA Nemotron โ€” both small (<32B) models served by Nebius Token Factory, selected by one env var: ```bash # OpenBMB MiniCPM (sponsor:openbmb) UNSTUCK_BACKEND=minicpm NEBIUS_API_KEY=... python app.py # NVIDIA Nemotron (sponsor:nvidia) โ€” 30B-A3B reasoning model, callable but less schema-reliable UNSTUCK_BACKEND=nemotron NEBIUS_API_KEY=... python app.py ``` MiniCPM-V is live-verified valid (5/5 in the bake-off). The Nebius Nemotron above is the **30B reasoning** model โ€” callable, but the *verified-valid* Nemotron is the 4B `nvidia/Nemotron-Mini-4B-Instruct` (run on Modal, 5/5). Override `MINICPM_MODEL` / `NEMOTRON_MODEL` (or `*_BASE_URL` + `*_API_KEY`) to point at any other host โ€” e.g. NVIDIA's own NIM endpoint at [build.nvidia.com](https://build.nvidia.com): ```bash # Nemotron on NVIDIA's own NIM (build.nvidia.com) UNSTUCK_BACKEND=nemotron \ NEMOTRON_BASE_URL=https://integrate.api.nvidia.com/v1 \ NEMOTRON_API_KEY=nvapi-... \ NEMOTRON_MODEL=nvidia/nemotron-3-nano-30b-a3b \ python app.py ``` ### Run on our fine-tuned model (`finetuned`) `UNSTUCK_BACKEND=finetuned` runs the app on [`art87able/unstuck-qwen2.5-0.5b-steps`](https://huggingface.co/art87able/unstuck-qwen2.5-0.5b-steps) โ€” a Qwen2.5-0.5B-Instruct LoRA we **trained on a Modal A10G GPU** by distilling 130 schema-valid breakdowns out of the strong serverless model, then merged and published to the Hub: ```bash pip install -r requirements.txt gradio torch transformers UNSTUCK_BACKEND=finetuned python app.py # loads the published model, runs locally ``` The whole pipeline is in [`scripts/finetune/`](https://github.com/art87able/unstuck/tree/main/scripts/finetune): `gen_dataset.py` (distillation) โ†’ `modal_finetune.py` (LoRA on Modal) โ†’ `modal_verify.py` (reloads the published model and asserts a schema-valid breakdown). Your history lives in your browser. Use the in-app **Export**/**Import** buttons to move it between devices. Source: https://github.com/art87able/unstuck (Codex Track)