Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .agents/skills/building/references/desktop.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Desktop worktrees

There are separate Tauri and GPUI Cargo workspaces and toolchains. Never assume one cache key or one native runtime verifies both.
There are two Cargo workspaces with their own toolchains and lockfiles: the root workspace (`apps/cli` and `crates/*`) and the desktop app's standalone workspace (`apps/desktop-gpui`). Never assume one cache key or one native runtime verifies both.

`warm --session <id> --source <idle-checkout>` snapshots prepared native dependencies into the Git-common cache, then creates a private copy-on-write clone in the worktree. `--rust` also warms `target/debug` and `apps/desktop-gpui/target/debug`. It excludes profiles, user media, release artifacts, and arbitrary contents of `target`.

Expand All @@ -16,6 +16,6 @@ Native runtime isolation is separate from build isolation. Cap has single-instan

Use `run --native` and `check --native` for expensive Rust compilation as well. This queues native work across sessions instead of launching twenty large builds at once. Complete compile checks before holding the lease with a long-lived native runtime. Source editing and independent web work can continue while a native job waits.

For v1, prefer a dedicated native runner/OS user with synthetic recordings and test credentials. Before any local native launch, explicitly verify its app identifier, data directory, recording library, frontend port, authentication callback, and existing process ownership. Do not launch it against the user's normal Cap profile. Native profile provisioning and parallel local Tauri/GPUI launch are not automated by this helper.
For v1, prefer a dedicated native runner/OS user with synthetic recordings and test credentials. Before any local native launch, explicitly verify its app identifier, data directory, recording library, frontend port, authentication callback, and existing process ownership. Do not launch it against the user's normal Cap profile. Native profile provisioning and parallel local desktop app launches are not automated by this helper.

Use the platform's actual Cap CLI to capture native demos. Linux Daytona evidence cannot close macOS ScreenCaptureKit, Windows capture, hardware GPU, microphone/camera, permissions, or updater gates. Retain a platform matrix in the PR and keep it draft when required native verification is missing.
16 changes: 7 additions & 9 deletions .config/hakari.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ resolver = "2"
# https://doc.rust-lang.org/rustc/platform-support.html
# Every target desktop-release.yml ships. Leaving a target out here leaves its
# platform-specific deps (windows-sys, libc, ...) un-unified, so the sidecar
# `cargo build -p cap` and Tauri's `cargo build -p cap-desktop` resolve
# different feature sets and recompile ~500 shared crates in the same job.
# `cargo build -p cap` and the desktop app's build of the same crates resolve
# different feature sets and recompile hundreds of shared crates in one job.
platforms = [
"x86_64-unknown-linux-gnu",
"x86_64-apple-darwin",
Expand All @@ -37,11 +37,11 @@ platforms = [
[traversal-excludes]
workspace-members = ["cap-muxer", "cap-muxer-protocol", "cap-verify-expect"]

# hakari unifies dev-dependencies as well, so left alone it pins tauri with its
# `test` feature and tokio `test-util` into every release binary and pulls the
# Tauri/WebKit stack into the standalone GPUI workspace. Only crates whose
# feature drift actually cascades through the sidecar and desktop builds stay
# in the hack; everything else keeps its natural per-binary resolution.
# hakari unifies dev-dependencies as well, so left alone it pins tokio
# `test-util` into every release binary and drags dev-only stacks into the
# standalone GPUI workspace. Only crates whose feature drift actually cascades
# through the sidecar and desktop builds stay in the hack; everything else
# keeps its natural per-binary resolution.
[final-excludes]
third-party = [
{ name = "softbuffer" },
Expand Down Expand Up @@ -79,8 +79,6 @@ third-party = [
{ name = "smallvec" },
{ name = "swift-rs" },
{ name = "syn" },
{ name = "tauri" },
{ name = "tauri-build" },
{ name = "tokio" },
{ name = "tokio-util" },
{ name = "toml" },
Expand Down
50 changes: 3 additions & 47 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ jobs:
runs-on: blacksmith-8vcpu-ubuntu-2404
outputs:
rust: ${{ steps.filter.outputs.rust }}
gpui: ${{ steps.filter.outputs.rust == 'true' || steps.filter.outputs.gpui == 'true' || steps.desktop-resources.outputs.desktop-resources == 'true' }}
tauri-plugins: ${{ steps.filter.outputs.tauri-plugins }}
gpui: ${{ steps.filter.outputs.rust == 'true' || steps.filter.outputs.gpui == 'true' }}
gpui-patches: ${{ steps.filter.outputs.gpui-patches }}
steps:
- name: Checkout
Expand All @@ -49,10 +48,7 @@ jobs:
gpui:
- '.gitattributes'
- 'apps/desktop-gpui/**'
- 'apps/desktop/src/assets/**'
- 'apps/desktop/src-tauri/src/recording_start_sound.rs'
- 'apps/media-server/src/__tests__/fixtures/**'
- 'packages/ui-solid/icons/**'
- 'scripts/build-desktop-binaries*'
- 'scripts/build-gpui-binary.sh'
- 'scripts/build-linux-packages.mjs'
Expand All @@ -62,33 +58,11 @@ jobs:
- 'scripts/finalize-macos-*'
- 'scripts/linux-bundle-config*'
- 'scripts/prepare-gpui-dependency*'
- 'scripts/run-gpui-build*'
- 'scripts/sync-desktop-versions.mjs'
- 'scripts/verify-gpui-release-inputs.mjs'
- 'scripts/verify-windows-stack.mjs'
gpui-patches:
- 'apps/desktop-gpui/patches/**'
- 'scripts/prepare-gpui-dependency.sh'
tauri-plugins:
- 'Cargo.lock'
- 'bun.lock'
- 'scripts/check-tauri-plugin-versions*'
- 'apps/desktop/package.json'

# Cap ships as the GPUI app, which embeds icons, sounds, assets and test
# data from apps/desktop. Only the Tauri app's own sources are skipped.
- name: Check for GPUI resources in apps/desktop
uses: dorny/paths-filter@v3
id: desktop-resources
with:
predicate-quantifier: every
filters: |
desktop-resources:
- 'apps/desktop/**'
- '!apps/desktop/src/**'
- '!apps/desktop/src-tauri/src/**'
- '!apps/desktop/src-tauri/tests/**'
- '!apps/desktop/src-tauri/gen/**'

typecheck:
name: Typecheck
Expand All @@ -106,8 +80,7 @@ jobs:

- name: Test workspace tooling
run: |
node --test scripts/bun-scripts.test.mjs scripts/check-tauri-plugin-versions.test.mjs
bun run --cwd apps/desktop vitest run scripts/prepare.test.js
node --test scripts/bun-scripts.test.mjs

- name: Test Loops profile sync
run: |
Expand Down Expand Up @@ -272,10 +245,8 @@ jobs:
shell: bash
run: cargo test --locked -p cap-utils -p cap-cli-install --lib

# cap-desktop is the Tauri app, which no longer ships; Cap is the GPUI app
# plus the cap-muxer and cap-cli sidecars built from this workspace.
- name: Run Clippy
run: cargo clippy --workspace --exclude cap-desktop --all-features --locked -- -D warnings
run: cargo clippy --workspace --all-features --locked -- -D warnings

lint-biome:
name: Lint (Biome)
Expand Down Expand Up @@ -500,18 +471,3 @@ jobs:
else
cargo +1.95.0 test -p gpui_windows --lib directx_atlas
fi

tauri-plugins:
name: Verify Tauri plugin versions
runs-on: blacksmith-8vcpu-ubuntu-2404
needs: changes
if: needs.changes.outputs.tauri-plugins == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4

- uses: ./.github/actions/setup-js

- name: Run verify
shell: bash
run: node scripts/check-tauri-plugin-versions.js
33 changes: 21 additions & 12 deletions .github/workflows/desktop-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ jobs:
releasePublished = !release.draft;

if (releasePublished)
throw new Error(`Release '${tag}' is already published: ${releaseUrl}. Bump apps/desktop/src-tauri/Cargo.toml before publishing a new build.`);
throw new Error(`Release '${tag}' is already published: ${releaseUrl}. Bump apps/desktop-gpui/Cargo.toml before publishing a new build.`);
else
core.notice(`Draft release '${tag}' already exists. Continuing build and upload.`);
}
Expand Down Expand Up @@ -287,20 +287,25 @@ jobs:
shell: bash
env:
BUILD_VERSION: ${{ inputs.version }}
# promote-nightly can rebuild a commit from before the Tauri app was
# removed, where apps/desktop/src-tauri/Cargo.toml was the version
# source, so that manifest is stamped too when it exists.
run: |
node -e '
const fs = require("fs");
const path = "apps/desktop/src-tauri/Cargo.toml";
const version = process.env.BUILD_VERSION;
let toml = fs.readFileSync(path, "utf8");
const re = /^version = ".*"$/m;
if (!re.test(toml)) {
console.error("package.version line not found in " + path);
process.exit(1);
const manifests = ["apps/desktop-gpui/Cargo.toml", "apps/desktop/src-tauri/Cargo.toml"];
for (const path of manifests.filter((path, index) => index === 0 || fs.existsSync(path))) {
let toml = fs.readFileSync(path, "utf8");
const re = /^version = ".*"$/m;
if (!re.test(toml)) {
console.error("package.version line not found in " + path);
process.exit(1);
}
toml = toml.replace(re, "version = \"" + version + "\"");
fs.writeFileSync(path, toml);
console.log("Stamped " + path + " with " + version);
}
toml = toml.replace(re, "version = \"" + version + "\"");
fs.writeFileSync(path, toml);
console.log("Stamped " + path + " with " + version);
'
node scripts/sync-desktop-versions.mjs

Expand Down Expand Up @@ -359,7 +364,7 @@ jobs:
free -h

# The same link used to exhaust commit on the 16GB Windows runner
# ("rustc-LLVM ERROR: out of memory" while linking cap-desktop), so
# ("rustc-LLVM ERROR: out of memory" while linking the desktop app), so
# raise the pagefile on the roomy D: disk, the Windows analog of the
# Linux swapfile above. Kept for headroom after the move to thin LTO.
- name: Increase pagefile size (Windows)
Expand Down Expand Up @@ -890,8 +895,12 @@ jobs:
- name: Re-sign Windows installer for the updater
if: ${{ runner.os == 'Windows' }}
shell: bash
working-directory: apps/desktop
run: |
# Commits from before the Tauri app was removed (promote-nightly)
# keep the Tauri CLI in apps/desktop.
tauri_dir=apps/desktop-gpui
[[ -f "$tauri_dir/package.json" ]] || tauri_dir=apps/desktop
cd "$tauri_dir"
BUNDLE_DIR="../../$CAP_BUNDLE/nsis"
for exe in "$BUNDLE_DIR"/*.exe; do
echo "Re-signing $(basename "$exe") for the updater..."
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/promote-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name: "promote-nightly"
# GitHub release, draft CrabNebula release on the default channel, published
# manually as usual.
#
# After promoting, bump apps/desktop/src-tauri/Cargo.toml on main past the
# After promoting, bump apps/desktop-gpui/Cargo.toml on main past the
# promoted version so future nightlies and stable releases version correctly.

on:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
uses: SebRollen/[email protected]
id: read_version
with:
file: apps/desktop/src-tauri/Cargo.toml
file: apps/desktop-gpui/Cargo.toml
field: "package.version"

- name: Compute nightly version
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
uses: SebRollen/[email protected]
id: read_version
with:
file: apps/desktop/src-tauri/Cargo.toml
file: apps/desktop-gpui/Cargo.toml
field: "package.version"

release:
Expand Down
16 changes: 8 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Repository Guidelines

Check failure on line 1 in AGENTS.md

View workflow job for this annotation

GitHub Actions / Lint (Biome)

format

File content differs from formatting output

## Pre-Generation Invariants (read BEFORE writing any code)

Expand All @@ -6,7 +6,7 @@

### Zero-tolerance rules
- **Default to no code comments. Add a comment only after solving a bug or working through a complex issue, and only when it captures non-obvious context that a future investigator or reviewer genuinely needs** — e.g. why the fix looks the way it does, the upstream/platform bug being worked around, a non-obvious invariant or trade-off chosen after investigation, or a link to the PR/issue that explains the decision. Bad cases that remain banned: narrating what the code does, restating types, JSDoc that paraphrases parameter names, "TODO: refactor" or "this should be cleaner" notes, and any comment that just describes the change you are currently making. When in doubt, prefer better naming/types over a comment. Applies to every language: Rust, TS, JS, Python, shell, SQL, TOML, etc.
- **Never hand-edit generated files**: `**/tauri.ts`, `apps/desktop/src-tauri/gen/**`, `packages/ui-solid/src/auto-imports.d.ts`, Drizzle migration SQL under `packages/database/migrations/`. These are regenerated (e.g. `tauri.ts` only on debug desktop runs) but stay committed because CI typecheck and fresh clones depend on them; commit binding changes alongside the Rust change that produced them. For database schema changes, run `bun run db:generate` and commit the generated SQL, snapshot, and journal changes alongside the schema change. Generating and committing these artifacts is required; modifying generated output by hand is prohibited. Note: `apps/desktop/src/utils/queries.ts` is hand-written, not generated — edit it normally.
- **Never hand-edit generated files**: Drizzle migration SQL under `packages/database/migrations/` and the hakari-managed section of `crates/workspace-hack/Cargo.toml`. These stay committed because CI and fresh clones depend on them. For database schema changes, run `bun run db:generate` and commit the generated SQL, snapshot, and journal changes alongside the schema change. Generating and committing these artifacts is required; modifying generated output by hand is prohibited.
- **Never start additional dev servers** (`bun run dev`, `bun run dev:web`, `bun run dev:desktop`, Docker services). Assume they are already running. The `/building` workflow may start a session-owned web server in its isolated worktree on an allocated port through its environment wrapper, or services inside its owned sandbox. This exception does not permit restarting shared services or launching a native app against the user's existing profile.

### Post-edit checks (run before you say "done")
Expand Down Expand Up @@ -41,7 +41,7 @@
- **Quotes: double.** `"foo"`, never `'foo'`, for JS/TS string literals.
- **`organizeImports: on`** — imports are sorted/grouped automatically; don't leave unused imports or hand-sort against the grain.
- **Recommended lint ruleset is on**, with `suspicious.noShadowRestrictedNames` disabled. Everything else (unused vars, `noExplicitAny`, dead code, etc.) applies.
- Desktop code under `apps/desktop/**` has a11y rules disabled; they are enforced everywhere else (`apps/web`, `packages/ui`, etc.).
- a11y rules are enforced everywhere (`apps/web`, `packages/ui`, etc.).
- CSS overrides: `noUnknownAtRules`, `noUnknownTypeSelector`, `noDescendingSpecificity` are off for `**/*.css`.

### TypeScript — strictness
Expand All @@ -50,30 +50,30 @@

## Project Structure & Modules
- Turborepo monorepo:
- `apps/desktop-gpui` (GPUI, ships as Cap), `apps/desktop` (Tauri v2 + SolidStart; last shipped in 0.6.0, kept for the dev harness), `apps/web` (Next.js), `apps/cli` (Rust CLI).
- `packages/*` shared libs (e.g., `database`, `ui`, `ui-solid`, `utils`, `web-*`).
- `apps/desktop-gpui` (the Cap desktop app: native Rust + GPUI, its own Cargo workspace), `apps/web` (Next.js), `apps/cli` (Rust CLI).
- `packages/*` shared libs (e.g., `database`, `ui`, `utils`, `web-*`).
- `crates/*` Rust media/recording/rendering/camera crates.
- `scripts/*`, `infra/`, and `packages/local-docker/` for tooling and local services.
- Marketing and lifecycle emails (copy, Loops journeys and campaigns, the email catalogue and voice guide) and their Loops tooling live in the private repo [CapSoftware/cap-marketing](https://github.com/CapSoftware/cap-marketing). View and edit them there. This repo keeps only the runtime profile sync in `packages/database/loops/` (with its tests and runners in `scripts/loops/`) and the transactional emails in `packages/database/emails/`.

## Build, Test, Develop
- Install: `bun install`; setup: `bun run env-setup` then `bun run cap-setup`.
- Dev: `bun run dev` (web+desktop). Desktop only: `bun run dev:desktop`. Web only: `bun run dev:web` or `cd apps/web && bun run dev`.
- Build: `bun run build` (Turbo). Desktop release: `bun run gpui:build <target>` (Cap ships as the GPUI app only).
- Build: `bun run build` (Turbo). Desktop release: `bun run gpui:build <target>` on the target platform.
- DB: `bun run db:generate` → `bun run db:push` → `bun run db:studio`.
- Docker: `bun run docker:up | docker:stop | docker:clean`.
- Quality: `bun run lint`, `bun run format`, `bun run typecheck`. Rust: `cargo build -p <crate>`, `cargo test -p <crate>`.

## Coding Style & Naming
- TypeScript / JS / JSON / CSS: **tab indent** and **double-quoted** strings, enforced by Biome (see `biome.json`). Do not configure per-file overrides.
- Rust: `rustfmt` default style + the denied clippy lints in the Pre-Generation Invariants above.
- Naming: files kebab‑case (`user-menu.tsx`); React/Solid components PascalCase; hooks `useX`; Rust modules snake_case; crates kebab‑case.
- Runtime: Node 24, Bun 1.4.4, Rust 1.88+, Docker for MySQL/MinIO.
- Naming: files kebab‑case (`user-menu.tsx`); React components PascalCase; hooks `useX`; Rust modules snake_case; crates kebab‑case.
- Runtime: Node 24, Bun 1.4.4, Rust 1.88 for the root workspace (`apps/desktop-gpui` pins its own toolchain), Docker for MySQL/MinIO.

(See **Pre-Generation Invariants** at the top of this file for the comments policy and the denied clippy/Biome patterns. Those are the source of truth — do not duplicate or weaken them here.)

## Testing
- TS/JS: Vitest where present (e.g., desktop). Name tests `*.test.ts(x)` near sources.
- TS/JS: Vitest where present (e.g., web). Name tests `*.test.ts(x)` near sources.
- Rust: `cargo test` per crate; tests in `src` or `tests`.
- Prefer unit tests for logic and light smoke tests for flows; no strict coverage yet.

Expand Down
Loading
Loading