Files
Void-Homelab/docs/superpowers/specs/2026-06-08-fold-in-timelapse-aiusage-design.md
root 4f97add050 docs(fold-in): spec for folding Timelapse + AI Usage into the Void
Cross-origin HTTPS iframe embeds as left-rail "Apps" items; standalone
URLs stay chromeless. phuryn gets aiusage.hynesy.com behind CF Access;
timelapse gets a Phase-1 palette/typography restyle. Targets alpha.27.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 14:32:05 +10:00

7.9 KiB
Raw Permalink Blame History

Design: Fold Timelapse + AI Usage into the Void

Date: 2026-06-08 Status: Approved (brainstorm), pending implementation plan Target version: void-server 2.0.0-alpha.27

Summary

Make the Timelapse app and the AI Usage (phuryn/claude-usage) dashboard first-class, navigable items in the Void's left rail, embedded as cross-origin HTTPS iframes. Each app remains reachable at its own *.hynesy.com URL, and when accessed there it shows only the bare app — no Void chrome, so there is no way to "backtrack" into the Void. The Timelapse app additionally gets a Phase1 restyle (palette + typography) to align with the Void aesthetic.

This is the fold-in feature. Three things are explicitly out of scope here and tracked separately:

  • The phuryn dashboard "not really working" functional fix (deferred by user).
  • The Timelapse Phase2 full visual match (preview-first follow-up).
  • Void 1 / CT 301 teardown (separate infra effort, sequenced after this).
  • Moving the existing Terminal rail item into the new section.

Background / current state

  • Void 2/project/src/void-v2, Express + hash-routed SPA, deployed to CT 311 (192.168.1.216), served at void.hynesy.com behind CF Access.
    • Sidebar (public/components/sidebar.js) has sections: Spaces, Agents, Navigate.
    • Embedding precedent: the Terminal item is an <iframe src="/terminal/"> that server.js reverse-proxies (with WebSocket upgrade) to ttyd on CT 300.
  • Timelapse/project/farm-timelapse, FastAPI + HTMX (Python) on CT 108, served at timelapse.hynesy.com (CF tunnel → Traefik on CT 100 → CT 108:8000, behind CF Access / Google IdP).
  • AI Usagephuryn/claude-usage, a Python-stdlib web SPA on CT 300 (192.168.1.212:8080). Its data source is CT 300's local /root/.claude/projects/**/*.jsonl (Claude Code transcripts). There is also a Sacred Valley card public/views/cards/ai_usage.js whose Full dashboard ↗ link currently points at the raw http://192.168.1.212:8080/.

Why phuryn stays on CT 300

Its entire data source is CT 300's local Claude Code transcripts. Relocating it to the Void CT would require continuously syncing those JSONL files across hosts for no benefit. Void already proxies to CT 300 for the Terminal, so CT 300 is an already-trusted backend.

Decisions

Decision Choice Rationale
Embed strategy A — cross-origin HTTPS iframes Both apps use root-relative paths; a same-origin prefix proxy would collide with Void's own routes (timelapse's hardcoded /browse…, phuryn's fetch('/api/…')). Cross-origin iframes to each app's own HTTPS origin sidestep all path rewriting.
phuryn hostname aiusage.hynesy.com New CF tunnel host → CT 300:8080 behind CF Access. Also adds auth to phuryn, which is currently unauthenticated on the LAN.
Timelapse standalone URL timelapse.hynesy.com (unchanged) Already HTTPS, no X-Frame-Options, directly frameable.
SV AI Usage card Keep as-is, retarget its link only Card stays; Full dashboard ↗ retargets to in-Void #/ai-usage.
Rail placement New "Apps" sidebar section Groups embedded external apps; Terminal stays under Navigate (moving it is out of scope).
Timelapse restyle Phase 1 = palette + typography only Fast, low-risk, no markup restructure. Phase 2 deferred.

Architecture

Void renders, per app, a thin Void-styled header bar + a full-height <iframe> pointing at the app's own HTTPS origin. No "back to Void" affordance is injected into either app, so standalone visits stay chromeless.

App Standalone URL Backend host Iframe src
Timelapse timelapse.hynesy.com (exists) CT 108 https://timelapse.hynesy.com
AI Usage aiusage.hynesy.com (new) CT 300:8080 https://aiusage.hynesy.com

Components

Void (CT 311, /project/src/void-v2)

  • public/router.js — add routes timelapse (#/timelapse) and ai-usage (#/ai-usage).
  • public/components/sidebar.js — add an "Apps" section with Timelapse and AI Usage nav items (active-highlight synced like existing items).
  • public/views/timelapse.js and public/views/aiusage.js — each mirrors public/views/terminal.js:
    • Void header bar: ◆ <Title>, an ↗ Open link to the standalone URL (target=_blank), and a ⟳ Reload button (f.src = f.src).
    • Full-height <iframe> with correct src. Timelapse iframe gets allow="fullscreen" for video playback.
    • No back-to-Void affordance inside the embedded app.
  • public/app.js — wire the two new view modules into the render switch (matching how terminal is dispatched).
  • public/views/cards/ai_usage.js (line ~33) — retarget Full dashboard ↗ from http://192.168.1.212:8080/ to in-Void #/ai-usage (drop target=_blank so it opens session-shared within the SPA). Card otherwise unchanged.
  • package.json / version string in server.js — bump to 2.0.0-alpha.27; CHANGELOG entry.

Cloudflare / infra (provisioned via CF API; creds in memory)

  • Traefik (CT 100) dynamic config: router for aiusage.hynesy.comhttp://192.168.1.212:8080. Wildcard *.hynesy.com DNS already targets the tunnel, so no new DNS record is required.
  • CF Access application for aiusage.hynesy.com — Google IdP + email allowlist, cloned from the existing timelapse Access app.

Timelapse restyle — Phase 1 (CT 108, /project/farm-timelapse)

  • Port Void's design tokens into tlcapture/static/style.css:
    • Palette: --bg #0a0a0e, --panel #14141c, --panel-2 #1c1c26, --border #2a2a36, --text #e8e6ed, --muted #888094, --accent #ff4f2e (blackflame), --ok/--warn/--bad as in Void.
    • Fonts: display Cinzel/Cormorant Garamond serif, body Cormorant Garamond, UI system-ui, mono JetBrains Mono.
  • Colors, typography, and surface backgrounds only. No markup restructure (that is Phase 2). The app keeps its own internal navigation/controls.

Data flow

No new data paths. phuryn keeps reading CT 300's local JSONL transcripts; only its exposure changes (LAN :8080 → additionally aiusage.hynesy.com via Traefik/CF Access). Timelapse is functionally untouched; only its CSS changes.

Error handling

Cross-origin iframes cannot report load status to the parent, so each Void view always surfaces an ↗ Open in new tab fallback in its header (usable even if the frame is blank) plus a ⟳ Reload. If CF Access ever shows a login wall inside the frame, the fallback link routes the user there at top level. Validating that CF Access SSO renders frame-inline (no login wall, given an existing session) is the first implementation step.

Testing

  • vitest + jsdom: router resolves #/timelapse and #/ai-usage; sidebar renders the two Apps items; each view mounts an iframe with the expected src; the SV card link points at #/ai-usage.
  • CF / infra: curl -I https://aiusage.hynesy.com → CF Access challenge when unauthenticated; 200 with a valid session/service token.
  • Playwright (webapp-testing): click each rail item → embed loads; visit timelapse.hynesy.com and aiusage.hynesy.com directly → no Void rail present.

Sequencing & safety

  1. Provision aiusage.hynesy.com (Traefik route + CF Access app); validate iframe SSO renders without a login wall before touching Void.
  2. Void changes: Apps section + routes + two views + SV-card retarget + version bump → alpha.27. Deploy via existing deploy/.
  3. Timelapse Phase1 restyle. Deploy via scripts/install.sh.

pct snapshot CT 311 before the Void deploy and CT 108 before the restyle deploy (backup-before-changes rule).

Out of scope (tracked elsewhere)

  • phuryn functional fix ("not really working").
  • Timelapse Phase2 full component restyle (preview first).
  • Void 1 / CT 301 teardown (separate infra effort).
  • Migrating the Terminal rail item into the Apps section.