--- title: loosecanvas emoji: πŸ•ΈοΈ colorFrom: indigo colorTo: purple sdk: docker app_port: 7860 pinned: false license: mit short_description: Local AI that turns talk into a trust-tagged map models: - unsloth/gemma-4-26B-A4B-it-qat-GGUF suggested_hardware: l4x1 startup_duration_timeout: 2h tags: - build-small-hackathon - track:wood - achievement:offgrid - achievement:llama - achievement:offbrand - achievement:fieldnotes - gradio - knowledge-graph - local-llm - llama.cpp - gemma - cytoscape - off-the-grid --- # loosecanvas πŸ•ΈοΈ **Talk through an idea. Watch it become a map β€” and decide which connections are real.** ## The problem LLMs assert. They hand you fluent text where a hard fact, a hedge, and a confident hallucination all look identical β€” so you can't tell what to trust, and the "knowledge" you build with them quietly rots. A knowledge graph an AI fills in on its own is just a prettier version of the same problem. ## The value prop: an AI that proposes, but never decides loosecanvas is a local, co-created understanding map. You chat; a small local model proposes concepts and connections; **you accept, reject, or edit every single proposal.** Each claim carries four independent trust fields that never collapse into one β€” `origin` (frozen at birth), `claim_type`, `support_state`, `review_state` β€” so a model's guess is permanently marked a guess until you say otherwise. Export drops unreviewed model-inferred claims, so the map you take with you is one you actually vouched for. Messy thinking in; a trustworthy, co-owned map out. ## TL;DR for judges - **Track:** 🌲 Thousand Token Wood β€” a small local model is the whole point. - **Off the grid:** zero cloud API calls. 100% local inference via **llama.cpp**. `base_url` is hardcoded to localhost; the API key is a dummy `not-needed`. - **Small model, load-bearing:** Gemma 4 26B-A4B (~25B active params, GGUF, QAT) β€” no fine-tune, stock Unsloth weights. The small-model constraint _forces_ the good UX: the human is in the loop because the model shouldn't be trusted blind. - **Off-brand UI:** a real custom **Svelte 5 + TypeScript Cytoscape.js** Gradio component, not a chatbot with a decorative graph beside it. - **Field notes:** a genuine build write-up ships with the submission (see links). ## Features - **Magic build from a paragraph.** Paste or write messy thoughts, press Send, and watch the graph assemble live as the model streams concepts and edges. - **Trust-tagged everything.** Model proposals land with an amber "awaiting review" badge. Accept, reject, or edit β€” origin is never silently upgraded. - **Color the clusters.** Community detection groups related ideas at a glance. - **Find a hidden connection.** Ask the model to surface a surprising cross-domain link, articulated in plain language β€” then judge it. - **Trust-gated export.** Unreviewed guesses are dropped on the way out. ## Demo - **Live Space:** https://huggingface.co/spaces/build-small-hackathon/loosecanvas (goes live when transferred to the org and made public) - **Demo video:** _TODO_ ## Architecture / system flow A turn is a negotiation, not autocomplete: ``` You chat ─▢ LangChain create_agent (local llama.cpp endpoint, streams tokens + tool calls) ─▢ agent tools accumulate proposed actions ─▢ validator + reducer DECIDE (pure: actions β†’ GraphPatch + ScenePatch) ─▢ graph repository + renderer adapter ─▢ RendererPatch ─▢ Cytoscape.js canvas ``` The LLM **proposes**; the validator and reducer **decide**. Rejected actions return a reason string the model can self-correct from. Three layers stay separate: the portable product artifact (graph + claims), the runtime/control plane, and the frontend (which owns positions and pan/zoom). The trust model is enforced in code, not by prompting. ## Tech stack | Layer | Choice | | ---------- | ------------------------------------------------------------------ | | Model | Gemma 4 26B-A4B-it-qat (GGUF, ~25B active params) β€” stock Unsloth | | Inference | llama.cpp OpenAI-compatible server, 100% local (127.0.0.1:8080) | | Agent loop | LangChain `create_agent`, streaming tools | | Backend | Python 3.13, FastAPI + Gradio, uvicorn (0.0.0.0:7860) | | Frontend | Svelte 5 + TypeScript, Cytoscape.js β€” custom Gradio component | | Deploy | Single self-contained Docker Space (llama-server + app, one image) | ## Hackathon badges | Tag | Why it's earned | | ------------------------ | --------------------------------------------------------------------- | | `track:wood` | A small local model (Gemma 4 26B-A4B) is the core of the product. | | `achievement:offgrid` | Zero cloud API calls; all inference is local llama.cpp. | | `achievement:llama` | llama.cpp is the inference runtime. | | `achievement:offbrand` | Real custom Svelte 5 + Cytoscape.js component, not default Gradio UI. | | `achievement:fieldnotes` | A genuine published build write-up ships with the submission. | ## Submission links | Item | Link | | ----------- | ----------------------------------------------------------------------------- | | Live Space | https://huggingface.co/spaces/build-small-hackathon/loosecanvas (on transfer) | | Demo video | _TODO_ | | Social post | _TODO_ | | Field notes | `submission/FIELD_NOTES.md` (in source repo) | | Source | GitHub β€” Joshua Sundance Bailey | | Team | @joshuasundance | ## Run it / deploy This Space runs a single self-contained Docker image: llama-server loads the GGUF in-container on `127.0.0.1:8080`, and uvicorn serves the app on `0.0.0.0:7860`. The model repo (`unsloth/gemma-4-26B-A4B-it-qat-GGUF`) is public β€” no token needed. `suggested_hardware: l4x1` is advisory; pick **Nvidia L4** in Space Settings to run on GPU. `startup_duration_timeout: 2h` covers the runtime model download (~13.6 GB) plus cold-GPU load. To run locally instead, see the source repo's `README.md`. Built for the **Build Small Hackathon** β€” Thousand Token Wood track.