process

Building ProFocusWork Part 4: The Desktop Shell and Review Layers

5 min read

ProFocusWork - Desktop App Shell

Part 3 covered the multi-AI review workflow. Today I built the actual desktop app - and learned that even with two AI reviewers, a human eye catches different things.

Phase 3: Desktop App Shell

The desktop app is the core of ProFocusWork. Menu bar is the primary interface (that’s Phase 11), but before I can build the menu bar, I need the app shell.

The stack:

The implementation agent handled the scaffolding. Dark theme with CSS custom properties, navigation sidebar, header component, placeholder pages for each route. Standard stuff.

What wasn’t standard: getting the Convex connection to work without auth.

The Auth Problem

Phase 6 adds Auth0. Right now, we’re in “no auth” mode - I just want to verify the app connects to Convex before implementing authentication.

The agent’s first attempt used api.projects.list to test the connection. Made sense - subscribe to projects, if we get data, we’re connected.

Problem: projects.list requires authentication. No auth means no data means connection timeout.

The fix was obvious in hindsight: create a public health check query.

// packages/convex/convex/health.ts
export const ping = query({
  args: {},
  handler: async () => {
    return { ok: true, timestamp: Date.now() };
  },
});

No requireAuth(), just a simple ping. Now the app can verify Convex is running without needing a user session.

Three Layers of Review

Here’s where it gets interesting. The implementation went through three review layers:

LayerWhat It Caught
Distinguished Engineer (Claude)CSP misconfiguration, type safety issues, missing cleanup
Codex CLI (GPT 5.2 xhigh)Auth assumption bug, fake error boundary, production CSP leak
Final VerificationWorking build, passing types and lint

The Distinguished Engineer caught 10 issues. Good stuff - CSP was disabled, Convex queries used string casting instead of typed imports, Google Fonts CDN broke offline-first.

But when I ran the approved code through Codex, it found more:

The Auth Assumption Bug

The connection test used api.projects.list, which requires auth. In a “no auth” phase, this always fails. The Distinguished Engineer didn’t catch this because it understood the code was correct - it just didn’t understand the project phase constraints deeply enough.

The Fake Error Boundary

The code had what looked like an error boundary:

{#if hasError}
  <div class="error-fallback">...</div>
{:else}
  <App />
{/if}

This isn’t a real error boundary. It only catches errors inside the onMount try/catch. Render-time errors? Child component errors? Uncaught. Svelte 5 has <svelte:boundary> for this - the agent should have used it.

Production CSP Leak

The production CSP included http://127.0.0.1:3210. That’s the local Convex dev server. Fine for development, but in production? That’s a security surface that shouldn’t exist.

The Fix Cycle (Again)

Same pattern as Part 3. Find issues, fix them, verify the fixes.

Me: Here are findings from my review...
Claude: [fixes issues]
Me: Run typecheck
Claude: Error - 'message' doesn't exist on type '{}'
Me: The error parameter in svelte:boundary needs typing
Claude: [fixes with `error: unknown`]
Me: Run typecheck
Claude: 0 errors

The snippet parameter in <svelte:boundary> is typed as unknown by default. Had to use error instanceof Error ? error.message : "Unknown error" to handle it properly.

What Actually Got Built

After all the review cycles, here’s the final desktop app:

Security:

Offline-First:

Type Safety:

Code Quality:

The Layered Review Insight

Part 3 established AI-reviewing-AI (Claude + Codex). Today proved why that second layer matters.

Review TypeCatches
Implementation AgentNothing - it wrote the code
Distinguished Engineer (Claude)Technical correctness, pattern adherence
Codex CLI (xhigh)Project phase context, subtle assumptions, edge cases

The Distinguished Engineer approved code that used an auth-required query in a no-auth phase. Technically correct code, wrong for the current state of the project. Codex caught it.

The multi-AI workflow from Part 3 isn’t just useful - it’s essential. Claude’s DE agent checks against patterns. Codex thinks adversarially about what could go wrong. Different models, different blind spots, better coverage.

Current State

Phase 1: Monorepo Foundation - completed
Phase 2: Convex Backend - completed
Phase 3: Desktop App Shell - completed

Commits:
- d78e0fd feat(desktop): add desktop app shell with Tauri 2 + Svelte 5
- 76010e4 fix(desktop): address review findings for Phase 3

Blocker:
- Rust not installed - need rustup before Tauri backend compiles

Next:
- Install Rust via rustup.rs
- Run `pnpm tauri:dev` to test full app
- Start Phase 4: Web App Shell with SvelteKit

The Vite frontend builds and runs at localhost:1420. Tauri backend needs Rust installed - that’s tomorrow’s first task.

What I Learned

Auth assumptions hide in innocent code. A query that “just lists projects” assumes a user exists. In a no-auth phase, that’s a bug.

Svelte 5 has real error boundaries. Use <svelte:boundary> with {#snippet failed(error, reset)}. Don’t fake it with conditional rendering.

CSP needs phase-awareness. Development endpoints shouldn’t leak into production CSP. Split them properly.

Multi-AI review is essential, not optional. Claude’s Distinguished Engineer checks patterns. Codex thinks adversarially. Together they catch what neither would alone.


Part 4 of the ProFocusWork build series. Part 5 will cover Phase 4: building the SvelteKit web dashboard.