Approved design for a Nuxt 3 site at claudedo.kuns.dev: "the page is the app" concept (3-island layout), build-time release fetch, and a Nitro release proxy that fronts the self-updater to hide the Gitea URL. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
9.9 KiB
ClaudeDo distribution website — design
Date: 2026-06-04
Status: Approved (design), ready for implementation planning
Repo: new standalone repo claudedo-web (not part of the ClaudeDo app solution)
Domain: claudedo.kuns.dev (Coolify on the user's VPS)
Purpose
Give friends a public place to download ClaudeDo and learn what it does, without sending them to the Gitea repo — so the source repo can be made more private. The site also fronts the app's self-updater so the Gitea URL is never exposed in the app or on the page.
Goals / non-goals
Goals
- Public, no-auth landing page at
claudedo.kuns.devthat matches the app's visual identity. - A primary download (installer
.exe) plus the portable.zipand checksums. - A release proxy that (a) feeds the page the current version and (b) serves the
app's self-updater the same JSON shape Gitea returns, with download URLs rewritten
to route through
claudedo.kuns.dev— hiding Gitea entirely.
Non-goals
- No docs site / getting-started page (the app ships an installer that handles setup).
- No changelog page (release notes already live on Gitea releases).
- No auth, accounts, analytics, or CMS.
- No CI/PR tooling for this repo beyond what Coolify needs to deploy.
Access & distribution decisions
- Access: fully public. No password/login. Relies on the unadvertised URL.
- Download source: build-time fetch of the latest Gitea release for the displayed version; actual download links route through the proxy and resolve the latest asset at request time (so a stale page still downloads the current build).
- Self-updater proxy: in scope for v1 (not deferred).
Tech stack
- Nuxt 3 (Vue 3) — single framework, single repo, single Coolify deploy.
- Nitro server routes for the release proxy + asset streaming.
- No DB, no auth, no secrets (the
releases/ClaudeDorepo is public). - Fonts: Inter Tight (display/body) + JetBrains Mono (mono), self-hosted or via
Google Fonts. Design tokens ported from
docs/UI Rewrite/design_handoff_claudedo/Tokens.axamlandstyles.css(moss/sage/peat palette, dark-first, 14px island radius, grain texture).
Concept: "the page IS the app"
The landing page is a faithful, in-browser rendering of the ClaudeDo desktop — the window chrome + the three islands — rather than a conventional marketing page. This is the chosen direction (over a cinematic single-window scroll and a worklog feed).
Layout — three islands on the app "desktop"
Desktop background = the app's layered moss gradients + 3px grain overlay. A centered
app window (titlebar + body) holds a 3-column island grid:
-
Lists island (left) — repurposed as page nav.
- Header "Lists" + a decorative search box (
Ctrl Kkbd chip). - "Pages" group: Overview · Features (6) · How it works · Screenshots (3) · Download, each with a colored swatch dot; active item gets the accent left-bar.
- Footer styled like the app's user footer: avatar, "For friends",
claudedo.kuns.dev.
- Header "Lists" + a decorative search box (
-
Tasks island (middle) — features rendered as task cards.
- Header: date eyebrow, big title (the hero line "Queue the work. Claude does it."),
a
running · reviewbadge, eye/gear icon buttons, and a subtitle. - A decorative "Add a task…" row.
- Six feature cards (circle check — done cards filled; title; a status chip
done/running/waiting for review; a star). The features:- Isolated worktrees
- The task queue
- Review & merge
- Live session log
- Per-list & per-task config
- Self-updating
- A "Ready" group with the final "↓ Download ClaudeDo" card.
- Header: date eyebrow, big title (the hero line "Queue the work. Claude does it."),
a
-
Detail island (right) — faithful to the reworked Task-Detail island.
- Source of truth for the detail visuals:
docs/superpowers/specs/2026-06-04-task-detail-redesign-design.md(the app's in-progress rework). The website's detail pane must track that design. - Three-zone stack:
- Task header — mono id (
#F01…), title, trash/gear action icons. - DETAILS bar —
DETAILSeyebrow +Edit/ copy /⋯, then a markdown body (headings, paragraphs, inlinecode, ordered/unordered lists) describing the feature. - WorkConsole docked at the bottom — traffic-light dots,
· N turns · +x −y, tabs Output / Actions / Session, and aCreated …footer.
- Task header — mono id (
- Per-feature mapping:
- Feature panels: markdown writeup in DETAILS + a short relevant Output log.
- "Review & merge": opens on the Actions tab with
Merge target+Open Diff/Approve & merge. - Download: DETAILS shows requirements (
.NET 8 Desktop Runtime,Claude CLI,Git); the Actions tab holds the install controls, withMerge targetrepurposed as a Build selector and buttons↓ Download installer/Portable .zip/checksums.txt.
- Source of truth for the detail visuals:
-
Statusbar (bottom) —
● Online · claudedo.kuns.dev · private build.
Interaction
- Clicking a task card selects it (accent bar + card highlight) and swaps the active detail panel; the WorkConsole tabs are clickable within a panel.
- All panels are server-rendered and present in the DOM, toggled by class — the page is fully readable and downloadable without JavaScript (progressive enhancement). Vue handles the selection state on the client.
Responsive
- ≤ ~1100px: drop the Detail island; show Lists + Tasks.
- ≤ ~780px: single column — the Tasks list; tapping a feature pushes to a full-screen Detail view (mirrors the app's narrow-window behavior) with a back affordance.
Server: release proxy (Nitro)
The app's ReleaseClient (src/ClaudeDo.Releases/ReleaseClient.cs) calls
{apiBase}/releases/latest and reads tag_name, name, and
assets[].browser_download_url; DownloadAsync GETs an asset URL directly.
GET /api/releases/latest— fetcheshttps://git.kuns.dev/api/v1/repos/releases/ClaudeDo/releases/latest, returns the same JSON shape, but everyassets[].browser_download_urlis rewritten from the Gitea URL tohttps://claudedo.kuns.dev/api/download/<encoded-asset-path>. Cached briefly (e.g. 5 min) server-side.GET /api/download/[...path]— reconstructs the Gitea asset URL from the path and streams the binary back (no redirect to Gitea, so the URL stays hidden). Sets appropriateContent-Type/Content-Disposition.server/utils/gitea.ts— shared base URL (GITEA_API,REPOfrom env), fetch helper, and the URL-rewrite/asset-path round-trip.- The page's download buttons point at the same
/api/download/...routes (with a stable "latest installer" path), so links never go stale between deploys.
App-side coordinating change (separate, in the ClaudeDo repo)
Point ReleaseClient's apiBase at https://claudedo.kuns.dev/api instead of the
Gitea default (one-line DI change where ReleaseClient/UpdateCheckService are
constructed). Tracked as a follow-up; not part of the claudedo-web repo. The proxy
path (/api/releases/latest) is chosen to match the existing
{apiBase}/releases/latest call so the parser is untouched.
Content / assets
- Screenshots (provided): main 3-column view (hero), diff review modal, worktrees
panel. Stored in
public/screenshots/. Placeholders sized for them until dropped in. - Copy: hero "Queue the work. Claude does it."; six feature writeups as above (final wording during implementation).
Error handling
- Build-time release fetch fails: render the page with a last-known/placeholder version label; download buttons still work because they resolve via the runtime proxy route.
- Proxy
/api/releases/latestupstream failure: return a 502/null-equivalent the way Gitea would on miss; the app'sUpdateCheckServicealready treats null/exception asCheckFailedand degrades gracefully. /api/downloadupstream failure: surface a 502; the button shows an error state.- No retries beyond a single upstream attempt for v1 (low traffic, friends-only).
Testing
- Vitest unit tests for
server/utils/gitea.ts: URL rewrite (Gitea → proxy) and the asset-path round-trip (proxy path → Gitea URL), and release-JSON shape preservation. - A light component smoke test that the page renders the islands and the download controls without JS errors.
- No real-network/Gitea calls in tests — mock the upstream fetch.
Deployment (Coolify)
- Dockerfile:
node:20-alpinebuild →nuxt build→ run.output/server/index.mjs. - Coolify app bound to
claudedo.kuns.devwith TLS via its reverse proxy. - Env:
GITEA_API(defaulthttps://git.kuns.dev/api/v1),REPO(releases/ClaudeDo),PUBLIC_BASE_URL(https://claudedo.kuns.dev) for URL rewriting. - Deploy on push to
main; re-deploy (or a periodic rebuild) refreshes the displayed version. No PR/CI tooling beyond Coolify's build.
Open risk
- The reworked Detail island in the app is still in flux. The website's detail pane
must be kept in sync with
2026-06-04-task-detail-redesign-design.md; expect a visual-polish pass once that rework lands.
Repo layout
claudedo-web/
├── nuxt.config.ts
├── app.vue
├── pages/index.vue # the one landing page
├── components/
│ ├── AppWindow.vue # window chrome + statusbar
│ ├── ListsIsland.vue # page nav
│ ├── TasksIsland.vue # feature cards + download card
│ ├── DetailIsland.vue # three-zone detail (header / DETAILS md / WorkConsole)
│ ├── WorkConsole.vue # tabs: Output / Actions / Session
│ └── content/ # per-feature markdown/blurbs + download panel
├── server/
│ ├── api/releases/latest.get.ts
│ ├── api/download/[...path].get.ts
│ └── utils/gitea.ts
├── assets/css/tokens.css # palette + type ported from Tokens.axaml/styles.css
├── public/screenshots/ # 3 PNGs
└── Dockerfile