| # HearthNet β Master Task & Improvement List |
|
|
| *Updated June 15, 2026 Β· Priority order: highest impact first* |
|
|
| --- |
|
|
| ## β
DONE β Hackathon Critical |
|
|
| | # | Task | Commit | |
| |---|------|--------| |
| | C1 | Demo video recorded and linked in README | ee40c33 | |
| | C2 | Social post on X @zX14_7 | ee40c33 | |
| | C3 | NVIDIA_API_KEY set in HF Space secrets | β | |
| | C4 | Deploy `app_nemotron.py` as second HF Space (`HearthNet-Nemotron`) | feat/nemotron-space | |
| | C5 | MiniCPM3-4B as default model in main Space (OpenBMB + Tiny Titan) | ee40c33 | |
| | C6 | Modal deploy fix β `scaledown_window` replacing deprecated param | ee40c33 | |
| | C7 | GitHub Codex commits pushed | ee40c33 | |
| | C8 | NVIDIA API key removed from Gradio frontend (SEC-1 critical fix) | 1c211eb | |
| | C9 | `/data` permission graceful fallback β Space no longer crashes | c9bf597 | |
|
|
| --- |
|
|
| ## β
DONE β Services Wired Up |
|
|
| Previously implemented in code but never connected or visible: |
|
|
| | # | Task | What was broken | Commit | |
| |---|------|----------------|--------| |
| | W1 | Nemotron tab added to main Gradio UI | `nemotron.py` existed, never imported | c021486 | |
| | W2 | Voice tab (STT + TTS) β new `voice.py` | STT/TTS services registered but no UI | c021486 | |
| | W3 | FederationService (M14) registered in `install_services()` | Never registered anywhere | c021486 | |
| | W4 | ImageGenerateService gets Florence2Backend at init | Was instantiated with empty `backends=[]` | c021486 | |
| | W5 | `edge-tts`, `faster-whisper`, `pytesseract` added to requirements | Not in requirements, so backends silently failed | c021486 | |
| | W6 | HearthNet theme applied to main app (purple/dark) | `hearthnet_theme` defined but never passed to `gr.Blocks` | latest | |
| | W7 | Custom CSS header, badges, animated status dot, button hover | Main app had zero custom styling | latest | |
| | W8 | Voice tab asyncio pattern fixed for Gradio async context | `get_event_loop()` fails inside Gradio's running loop | latest | |
|
|
| --- |
|
|
| ## π΄ P0 β Must fix before next demo |
|
|
| ### P0-1 β Image tab: upload β Florence2 describe |
| **Impact:** Shows off Florence2 + vision capability β judge can upload a photo and see AI describe it |
| **Effort:** 1 hour |
| **File to create:** `hearthnet/ui/tabs/image.py` |
| **Capability:** `img.describe@1.0` |
| **Add to `ui/app.py`:** `from hearthnet.ui.tabs.image import build_image_tab` + `with gr.Tab("πΌ Image"): build_image_tab(bus)` |
|
|
| ```python |
| # Minimal implementation: |
| def build_image_tab(bus): |
| img_input = gr.Image(type="filepath", label="Upload image") |
| describe_btn = gr.Button("π Describe with Florence2", variant="primary") |
| description_out = gr.Textbox(label="Description", lines=4) |
| |
| def _describe(path): |
| import base64 |
| with open(path, "rb") as f: |
| b64 = base64.b64encode(f.read()).decode() |
| result = _run(bus.call("img.describe", (1,0), {"input": {"image_b64": b64}})) |
| return result.get("output", {}).get("caption", result.get("caption", str(result))) |
| |
| describe_btn.click(_describe, inputs=[img_input], outputs=[description_out]) |
| ``` |
|
|
| ### P0-2 β OCR tab: upload scan/PDF β text |
| **Impact:** Tesseract/TrOCR β a common real-world need |
| **Effort:** 45 min |
| **File to create:** `hearthnet/ui/tabs/ocr.py` |
| **Capability:** `ocr.image@1.0`, `ocr.pdf@1.0` |
|
|
| ```python |
| def build_ocr_tab(bus): |
| ocr_input = gr.File(label="Upload image or PDF", file_types=[".png",".jpg",".pdf"]) |
| ocr_btn = gr.Button("π Extract Text", variant="primary") |
| ocr_out = gr.Textbox(label="Extracted text", lines=10) |
| |
| def _ocr(file_path): |
| cap = "ocr.pdf" if file_path.endswith(".pdf") else "ocr.image" |
| import base64 |
| with open(file_path, "rb") as f: |
| b64 = base64.b64encode(f.read()).decode() |
| result = _run(bus.call(cap, (1,0), {"input": {"file_b64": b64}})) |
| return result.get("output", {}).get("text", str(result)) |
| |
| ocr_btn.click(_ocr, inputs=[ocr_input], outputs=[ocr_out]) |
| ``` |
|
|
| ### P0-3 β Translation tab: text + language β translated text |
| **Impact:** NLLB-200 covers 200 languages β real differentiator |
| **Effort:** 30 min |
| **File to create:** `hearthnet/ui/tabs/translation.py` |
| **Capability:** `trans.text@1.0` |
|
|
| ```python |
| def build_translation_tab(bus): |
| src_text = gr.Textbox(label="Text to translate", lines=5) |
| src_lang = gr.Textbox(label="Source language", value="en") |
| tgt_lang = gr.Textbox(label="Target language", value="de") |
| translate_btn = gr.Button("π Translate", variant="primary") |
| out_text = gr.Textbox(label="Translation", lines=5) |
| |
| def _translate(text, src, tgt): |
| result = _run(bus.call("trans.text", (1,0), |
| {"params": {"source_lang": src, "target_lang": tgt}, |
| "input": {"text": text}})) |
| return result.get("output", {}).get("text", str(result)) |
| |
| translate_btn.click(_translate, inputs=[src_text, src_lang, tgt_lang], outputs=[out_text]) |
| ``` |
|
|
| --- |
|
|
| ## π P1 β High value, medium effort |
|
|
| ### P1-1 β Apply styled HTML headers to ALL tabs |
| **Current state:** Only voice.py and nemotron.py have styled section headers. Ask, Chat, Mesh, etc. have plain Markdown. |
| **Fix:** Add a `gr.HTML(...)` styled section header at the top of each `build_*_tab()` function, matching the gradient style in `voice.py`. |
|
|
| ### P1-2 β Rate limiting on `/bus/v1/call` and `/relay/v1/*` |
| **File:** `app.py` β `_mount_bus_endpoints()` |
| **Fix:** Wire `RateLimiter` from `hearthnet/bus/backpressure.py` |
| ```python |
| from hearthnet.bus.backpressure import RateLimiter |
| _limiter = RateLimiter(max_calls=60, window_seconds=60) |
| @app.middleware("http") |
| async def _rate_limit(request, call_next): |
| ip = request.client.host if request.client else "unknown" |
| if request.url.path.startswith(("/bus/v1", "/relay/v1")): |
| if not _limiter.allow(ip): |
| return JSONResponse({"error": "rate_limited"}, status_code=429) |
| return await call_next(request) |
| ``` |
| |
| ### P1-3 β Capability token expiry enforcement |
| **File:** `hearthnet/bus/router.py` |
| **Fix:** Check `token.exp < time.time()` before routing β `exp` is stored in the token but never validated. |
| |
| ### P1-4 β E2E encryption as default in chat (M23) |
| **File:** `hearthnet/services/chat/service.py` |
| **Status:** X3DH + Double Ratchet implemented in `hearthnet/crypto/` but `ChatService.send()` sends plaintext |
| **Fix:** Thread ratchet state through `ChatService._sessions` dict, encrypt payload before bus dispatch. |
| |
| ### P1-5 β Wire `node.start()` properly in `app.py` |
| **File:** `app.py` |
| **Currently:** `node.install_services()` called manually β skips mDNS, transport start, gossip sync |
| **Fix:** |
| ```python |
| # Replace: |
| _node.install_services(corpus="community") |
| # With (in a thread or via asyncio.get_event_loop): |
| loop.run_until_complete(_node.start(corpus="community")) |
| ``` |
| |
| ### P1-6 β Gossip sync between nodes (X02) |
| **File:** `hearthnet/node.py` β add to `node.start()` after step 9 |
| **Fix:** |
| ```python |
| from hearthnet.events.sync import SyncServer |
| self._sync_server = SyncServer(self._event_log, self.peers) |
| asyncio.create_task(self._sync_server.run()) |
| ``` |
| Enables marketplace posts and RAG documents to auto-replicate across mesh nodes. |
| |
| --- |
| |
| ## π‘ P2 β Medium value |
| |
| ### P2-1 β Evidence UI tab (M30) |
| **Capabilities:** `evidence.claim.add`, `evidence.claim.attest`, `evidence.claim.dispute` |
| **Service:** `EvidenceService` β registered in research mode (`install_extended_services(research=True)`) |
| **File to create:** `hearthnet/ui/tabs/evidence.py` |
| **Add to ui/app.py** once implemented. |
| |
| ### P2-2 β Civil Defense UI tab (M31) |
| **Capabilities:** `civdef.alert.issue`, `civdef.cert.*`, `civdef.audit.chain` |
| **Service:** `CivilDefenseService` β registered in research mode |
| **File to create:** `hearthnet/ui/tabs/civdef.py` |
|
|
| ### P2-3 β Routing trace as flow chart (U2) |
| **Current state:** Routing trace shown as plain text in Ask tab |
| **Fix:** Render as HTML/Mermaid flow diagram showing scored candidates and winner. |
|
|
| ### P2-4 β Peer capability matrix in Mesh tab (U5) |
| **File:** `hearthnet/ui/tabs/mesh.py` |
| **Add:** Table showing each discovered peer and their capabilities. |
|
|
| ### P2-5 β Dark mode toggle |
| **File:** `hearthnet/ui/app.py` |
| **Note:** `hearthnet/ui/theme.py` already has `emergency_theme` as a dark variant. Add a toggle. |
|
|
| ### P2-6 β Model selection UI in Settings tab |
| **Current state:** Model is fixed at startup via `MODEL_ID` env var |
| **Fix:** Add a dropdown in Settings showing available registered backends + restart hint. |
|
|
| ### P2-7 β Relay hub rate limiting |
| **File:** `hearthnet/transport/relay_hub.py` |
| **Fix:** Max 5 join attempts per IP per minute to prevent roster flooding. |
|
|
| --- |
|
|
| ## π’ P3 β Future / research |
|
|
| ### P3-1 β ShardServer.forward() for distributed inference (M26) |
| **File:** `hearthnet/distributed_inference/shard.py:75` β `NotImplementedError` |
| **Requires:** torch model slicing, attention head partitioning across nodes |
|
|
| ### P3-2 β FedLearnCoordinator.aggregate() (M28) |
| **File:** `hearthnet/fedlearn/coordinator.py:95` β `NotImplementedError` |
| **Requires:** peft, LoRA delta accumulation, secure aggregation protocol |
|
|
| ### P3-3 β LoRa hardware serial port (M29) |
| **File:** `hearthnet/lora/service.py:96` β silent stub without pyserial |
| **Fix:** `serial.Serial("/dev/ttyUSB0", 9600)` + add `pyserial>=3.5` to requirements |
|
|
| ### P3-4 β Browser β Python mesh bridge |
| **Files:** `webagent/src/mesh/browsermesh.js` (PeerJS/WebRTC) |
| **Status:** Browser mesh and Python relay run as separate isolated meshes |
| **Fix:** Bidirectional WebRTCβmailbox translation, ICE/TURN server |
|
|
| ### P3-5 β RelayDiscovery.start() (Phase 2 peer discovery) |
| **File:** `hearthnet/discovery/relay.py:8` β `NotImplementedError` |
| **Fix:** Poll `/relay/v1/roster` on a timer, add discovered peers to `PeerRegistry` |
|
|
| ### P3-6 β Publish to PyPI |
| **Command:** `python -m build && twine upload dist/*` |
| **Note:** `pyproject.toml` is ready |
|
|
| ### P3-7 β Docker image publish |
| **File:** `Dockerfile.slim` exists |
| **Command:** `docker build -t hearthnet:latest . && docker push ghcr.io/ckal/hearthnet:latest` |
|
|
| --- |
|
|
| ## π All Tasks β Status at a Glance |
|
|
| | Priority | Task | Status | |
| |----------|------|--------| |
| | C1βC9 | Hackathon critical items | β
All done | |
| | W1βW8 | Service/UI wiring | β
All done | |
| | P0-1 | πΌ Image describe tab | β
Done | |
| | P0-2 | π OCR tab | β
Done | |
| | P0-3 | π Translation tab | β
Done | |
| | P1-1 | Styled headers on all tabs | β
Done | |
| | P1-2 | Rate limiting on bus/relay | β³ Open | |
| | P1-3 | Token expiry enforcement | β³ Open | |
| | P1-4 | E2E encryption default | β³ Open | |
| | P1-5 | node.start() wiring | β³ Open | |
| | P1-6 | Gossip sync | β³ Open | |
| | P2-1 | Evidence UI tab | β³ Open | |
| | P2-2 | CivilDefense UI tab | β³ Open | |
| | P2-3 | Routing trace flow chart | β³ Open | |
| | P2-4 | Peer capability matrix | β³ Open | |
| | P2-5 | Dark mode toggle | β³ Open | |
| | P2-6 | Model selection UI | β³ Open | |
| | P2-7 | Relay hub rate limiting | β³ Open | |
| | P3-1 | M26 distributed inference | β³ Future | |
| | P3-2 | M28 federated learning | β³ Future | |
| | P3-3 | M29 LoRa hardware | β³ Future | |
| | P3-4 | BrowserβPython mesh bridge | β³ Future | |
| | P3-5 | RelayDiscovery.start() | β³ Future | |
| | P3-6 | PyPI publish | β³ Future | |
| | P3-7 | Docker image publish | β³ Future | |
|
|
| --- |
|
|
| ## See Also |
|
|
| - [`docs/ENV.md`](../ENV.md) β all environment variables, secrets, and model reference |
| - [`docs/SECURITY_FINDINGS.md`](../SECURITY_FINDINGS.md) β SEC-1 through SEC-8 with fixes |
| - [`hackathon_final_step.md`](../../hackathon_final_step.md) β project status and prize tracking |
|
|