# Platform Parity

> Audit and enforce feature parity between web (apps/web) and desktop (apps/desktop) platforms. Use when adding features, reviewing code placement, checking for drift between platforms, or validating that shared packages are used correctly. Triggers on mentions of "parity", "drift", "platform sync", "shared component", or "web vs desktop".

- Skill: `qdhenry/platform-parity` (Agent Skill)
- Install (CLI): `npx skillmds@latest add qdhenry/platform-parity`
- Raw SKILL.md: https://api.skillmd.com/api/skills/qdhenry/platform-parity/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: qdhenry (https://skillmd.com/u/qdhenry)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/qdhenry/platform-parity

---


# Platform Parity Auditor

Enforce feature parity and correct layer placement across Foundry's multi-platform monorepo. Prevents drift between `apps/web/` (Next.js) and `apps/desktop/` (Tauri/Vite/React), and ensures shared packages (`packages/ui/`, `packages/types/`) are used correctly.

**Target structure** (from `docs/plans/bun_workspace_tauri_implementation_plan.md`):

```
Foundry-App/
  convex/                       # Stays at root
  packages/
    types/                      # @foundry/types — shared type definitions
    ui/                         # @foundry/ui — shared sandbox HUD components
      src/sandbox/backend.ts    # ISandboxBackend interface
  apps/
    web/                        # Next.js 15 + App Router
    desktop/                    # Tauri 2 + Vite + React 19
  sandbox-worker/
  agent-service/
```

## Audit Modes

When invoked, ask the user which mode to run (or run all if they say "full audit"):

### 1. Drift Audit

Scan both platforms for parallel implementations that should be shared.

**Run these searches:**

```
Glob: apps/web/src/components/**/*.tsx
Glob: apps/desktop/src/components/**/*.tsx
```

Compare filenames across both trees. Flag:
- **Identical names** — same component name in both `apps/web/` and `apps/desktop/` (strong candidate for extraction to `packages/ui/`)
- **Similar purpose** — components with different names but overlapping functionality (e.g., `WebLogViewer` vs `DesktopLogStream`)
- **Duplicated hooks** — custom hooks that exist in both apps

Also check for type duplication:

```
Grep: "export (type|interface|enum)" in apps/web/src/**/*.ts
Grep: "export (type|interface|enum)" in apps/desktop/src/**/*.ts
```

Flag any type definitions that exist in both apps but not in `packages/types/`.

**Output:** Table of duplicated components/types with recommendation (extract to shared, keep platform-specific, or merge).

### 2. Layer Placement Check

When reviewing new or modified code, verify it lives in the correct layer.

**Rules:**

| Code Type | Correct Location | Detection Pattern |
|-----------|-----------------|-------------------|
| Pure React components (no framework imports) | `packages/ui/` | No imports from `next/*`, `@clerk/nextjs`, `@tauri-apps/*`, `react-router-dom` |
| Types, validators, constants | `packages/types/` | `export type`, `export interface`, `export enum`, `export const` with no runtime deps |
| Next.js-coupled code | `apps/web/` only | Imports `useRouter` from `next/navigation`, `next/link`, `next/dynamic`, `@clerk/nextjs`, `next/image` |
| Tauri-coupled code | `apps/desktop/` only | Imports `invoke` from `@tauri-apps/api`, `@tauri-apps/*` |
| Convex queries/mutations | Can live in shared or either app | Imports from `convex/react` or generated `_generated/api` |

**Run these checks:**

```
# Next.js imports in shared packages (VIOLATION)
Grep: "from ['\"]next/" in packages/**/*.{ts,tsx}
Grep: "from ['\"]@clerk/nextjs" in packages/**/*.{ts,tsx}

# Tauri imports in shared packages (VIOLATION)
Grep: "from ['\"]@tauri-apps" in packages/**/*.{ts,tsx}

# Next.js imports in desktop app (VIOLATION)
Grep: "from ['\"]next/" in apps/desktop/**/*.{ts,tsx}
Grep: "from ['\"]@clerk/nextjs" in apps/desktop/**/*.{ts,tsx}

# Tauri imports in web app (VIOLATION)
Grep: "from ['\"]@tauri-apps" in apps/web/**/*.{ts,tsx}

# Pure React in app-specific dirs (candidate for extraction)
# Look for components with no framework imports
```

**Output:** List of violations with file path, import statement, and recommended fix.

### 3. Abstraction Seam Validation

The three critical interfaces must not be bypassed:

#### ISandboxBackend

Shared sandbox components in `packages/ui/` must use the `ISandboxBackend` interface, never call Convex actions or Tauri commands directly.

```
# Direct Convex sandbox calls in shared UI (VIOLATION)
Grep: "useMutation.*sandbox" in packages/ui/**/*.{ts,tsx}
Grep: "useAction.*sandbox" in packages/ui/**/*.{ts,tsx}
Grep: "(api as any)\.sandbox" in packages/ui/**/*.{ts,tsx}

# Direct Tauri invoke in shared UI (VIOLATION)
Grep: "invoke\(" in packages/ui/**/*.{ts,tsx}
```

#### Auth Adapter

Shared components must not import auth providers directly.

```
# Direct Clerk imports in shared packages (VIOLATION)
Grep: "from ['\"]@clerk/nextjs" in packages/**/*.{ts,tsx}
Grep: "from ['\"]@clerk/clerk-react" in packages/**/*.{ts,tsx}
Grep: "useOrganization|useUser|useAuth" in packages/ui/**/*.{ts,tsx}
```

Shared components should receive auth context via props or a framework-agnostic adapter.

#### Router Adapter

Shared components must not import routing libraries directly.

```
# Direct router imports in shared packages (VIOLATION)
Grep: "from ['\"]next/navigation" in packages/**/*.{ts,tsx}
Grep: "from ['\"]next/link" in packages/**/*.{ts,tsx}
Grep: "from ['\"]react-router-dom" in packages/**/*.{ts,tsx}
```

Shared components should use a `NavigationAdapter` or receive navigation callbacks as props.

**Output:** Pass/fail for each seam with specific violations listed.

### 4. Parallel Implementation Detection

Deep scan for code duplication across platforms.

```
# Components with identical names
Glob: apps/web/src/components/**/*.tsx → extract basenames
Glob: apps/desktop/src/components/**/*.tsx → extract basenames
# Intersect the two lists

# Similar function signatures
Grep: "export (default )?(function|const) \w+" in apps/web/src/**/*.{ts,tsx}
Grep: "export (default )?(function|const) \w+" in apps/desktop/src/**/*.{ts,tsx}
# Compare exported function names

# Duplicate type definitions
Grep: "export (type|interface) \w+" in apps/web/src/**/*.ts
Grep: "export (type|interface) \w+" in apps/desktop/src/**/*.ts
# Flag any that aren't in @foundry/types
```

**Known framework-agnostic components** (from current codebase analysis — strong extraction candidates):
- `SandboxLogStream` — pure log rendering
- `ChatPanel` — chat UI (needs `ISandboxBackend` for message sending)
- `SandboxTerminal` — terminal emulator (needs WebSocket URL from backend)
- `SandboxStatusBadge` — status display
- `RuntimeModeBadge` — runtime mode display
- `StageProgress` — setup stage progress bar
- `SandboxFileChanges` — file diff viewer

**Known platform-coupled components** (must stay in their respective apps):
- `SandboxHUD` — uses `useRouter` from `next/navigation`
- `SandboxEditor` — uses `next/dynamic`
- `SandboxManagerPage` — uses `next/link`, `@clerk/nextjs`
- `SandboxSettingsPage` — uses `next/link`, `@clerk/nextjs`

**Output:** List of parallel implementations with extraction recommendation.

### 5. Schema Compatibility Check

Verify `convex/schema.ts` supports both runtimes where needed.

```
# Check for runtime field on session tables
Grep: "runtime" in convex/schema.ts

# Expected fields on sandboxSessions:
# runtime: v.optional(v.union(v.literal("cloud"), v.literal("local")))
# localDeviceId: v.optional(v.string())
# localDeviceName: v.optional(v.string())

# Check for runtime-aware indexes
Grep: "by_runtime" in convex/schema.ts

# Check that new Convex functions exist for local execution
Grep: "startLocal|reportLocalCompletion|appendBatchFromDesktop" in convex/sandbox/**/*.ts
```

**Output:** Schema readiness checklist with pass/fail per requirement.

## Full Audit

When the user requests a "full audit" or "parity check", run all 5 modes sequentially and produce a summary report:

```
## Platform Parity Report

### Drift Audit
- X components duplicated across platforms
- Y types duplicated (should be in @foundry/types)

### Layer Placement
- X violations found
- [list each violation]

### Abstraction Seams
- ISandboxBackend: PASS/FAIL
- Auth Adapter: PASS/FAIL
- Router Adapter: PASS/FAIL

### Parallel Implementations
- X identical components found
- Y similar function signatures

### Schema Compatibility
- Runtime field: PRESENT/MISSING
- Runtime index: PRESENT/MISSING
- Local execution functions: X/3 found
```

## When to Trigger

Run this skill proactively when:
- Adding a new component or feature that could apply to both platforms
- Moving files between `apps/` and `packages/`
- Reviewing PRs that touch `packages/ui/` or `packages/types/`
- After a batch of changes to either platform
- Before a release to verify no drift has accumulated
- When someone asks about "parity", "drift", "platform sync", or "web vs desktop"

