AGENTS.md Β· git:20261028.397214b Β· 2026-10-28 Β· sha256 47721da117b9bb9a
AGENTS.md git:20261028.397214bB
Immutable. This exact content never changes and is served at /api/v1/blob/47721da117b9bb9a.
# Skills Desktop Electron desktop app (macOS) for visualizing Skills symlink status across AI agents. - Never use direct `fs` access in the renderer when Context Isolation is enabled; use preload IPC instead. - Build macOS `APPLE_KEYCHAIN_PROFILE=skills-desktop pnpm build:mac` - For UI, visual polish, layout, motion, and design-token changes, read `DESIGN.md` first and follow it as the design source of truth. ## Workspace pnpm workspace, one root lockfile. Run scripts from the repo root (they delegate via `pnpm --filter`). See `ARCHITECTURE.md` / `CONTRIBUTING.md`. | Package | Path | Notes | | ----------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------- | | `skills-desktop` | `apps/desktop` | Electron app. **Owns the app version.** Never rename the package: it derives `app.getName()` / userData | | `skills-desktop-website` | `apps/website` | Next.js site + `/api/rpc` Unsplash proxy. Vercel Root Directory = `apps/website` | | `@skills-desktop/unsplash-contract` | `packages/unsplash-contract` | Shared oRPC contract/limits. TS source export; relative imports need explicit `.ts` | - Shared deps go in `pnpm-workspace.yaml` `catalog:` and are referenced as `"catalog:"` (`catalogMode: strict`); `pnpm sherif` enforces consistency - Workspace packages must stay **devDependencies** of `apps/desktop` so electron-vite bundles them; `pnpm check:bundled-workspace` (CI `build` job) fails otherwise - Website-only commands: `pnpm --filter skills-desktop-website <script>` ### π΄ Releases β Use `/electron-release` ONLY `/electron-release` is the single source of truth for the entire release pipeline: **version bump β notarized build β ZIP rename β GitHub release β website URL update β artifacts upload** **Forbidden:** - `/ship` MUST NOT bump the app version in `apps/desktop/package.json`. Version bumps are owned exclusively by `/electron-release`. The root `package.json` has no version. - Manual `gh release create` outside `/electron-release` (skips notarization check, ZIP rename, website update β auto-update breaks) - Manual edit of the `apps/desktop/package.json` `"version"` field For local production build verification (no release): ```bash APPLE_KEYCHAIN_PROFILE=skills-desktop pnpm build:mac ``` Without `APPLE_KEYCHAIN_PROFILE`: signing succeeds but notarization fails β Gatekeeper blocks the app. Artifacts land in `apps/desktop/dist/`. `/electron-release` runs the release scripts in order: `pnpm release:prepare-assets` (notarize + staple DMGs, rewrite their `latest-mac.yml` hashes, hyphenate ZIPs) β `gh release create` β `pnpm release:bump-website` β `pnpm release:verify` (must print `LIVE_VERIFY_ALL_OK`). ## Skill Execution Contract When a user explicitly invokes a skill, treat the skill document as the controlling workflow for that turn. Do not narrow the task to only the literal wording after the skill reference when the skill defines a broader end-to-end procedure. Execute the skill's required phases unless the user explicitly limits scope, a step is impossible, or continuing would be unsafe. If stopping early, state which skill step is being skipped and why. ## Agent skills ### Issue tracker GitHub Issues on `laststance/skills-desktop` via the `gh` CLI. See `docs/agents/issue-tracker.md`. ### Triage labels Five canonical roles, default label strings. See `docs/agents/triage-labels.md`. ### Domain docs Single-context: `CONTEXT.md` + `docs/adr/` at the repo root. See `docs/agents/domain.md`. ## Gotchas - **`*.browser.test.tsx`** runs in the Chromium lane via vitest browser mode. Vitest 4 projects need `dedupe + optimizeDeps` duplicated inline or React context breaks across files - **`npx skills remove <name>` defaults to local scope** while `npx skills add` defaults to global. Always pass `--global` for uninstall hints surfaced to users β see `SkillRowMarketplace.tsx` installed badge `aria-label` - **Port 9222 sticks** if `pnpm dev` died unclean. `kill-port 9222` (or `pkill -f electron`) before relaunching - **`@laststance/redux-storage-middleware` must stay β₯ 0.5.1, and `createReportingLocalStorage` must rethrow a rejected write** β the middleware retries a failed save on the next action only when `setItem` throws. 0.5.0+ still hydrates when the startup migration write-back throws (0.4.x set hydration to `error` and booted on defaults with saves off). 0.5.1+ keeps the two instances in `store.ts` (settings + renderer preferences on one store) from reacting to each other's `HYDRATE_COMPLETE`, which cancelled the settings retry. Swallowing the error silently drops quota-failed writes. Guarded by the quota-retry tests in `rendererPreferencesPersistence.test.ts` and the full-localStorage boot tests in `store.test.ts` - **Keep `navigator.locks.request` callbacks `async`** β Node 24's Web Locks never releases a lock whose callback throws synchronously, so every later request on that key hangs in node-lane tests (Chromium releases it). An `async` callback turns the throw into a rejection that frees the lock - **`ELECTRON_RUN_AS_NODE` breaks `pnpm test:e2e`** when the host is itself an Electron app (e.g. Devin Desktop): Playwright's `--remote-debugging-port` is rejected as a Node "bad option" and every launch fails. Run `env -u ELECTRON_RUN_AS_NODE pnpm test:e2e` ## Quality Gate Before opening or merging a PR, run the fast gates first: ```bash pnpm validate ``` Runs thirteen gates in one flat `run-p`: `sherif`, `lint`, `lint:contract`, `test`, `test:contract`, `typecheck`, `typecheck:e2e`, `typecheck:contract`, `validate:website`, `fallow:dead-code`, `fallow:dupes`, `fallow:health`, and `storybook:build`. Website validation includes its tests, lint, build and typecheck. Fallow runs from the root over all three packages. Hosted macOS CI runs `VITEST_MAX_WORKERS=1 pnpm validate --max-parallel 1` to bound concurrency. `pnpm format:check` runs as its own CI job. Only after it passes, run the Electron e2e suite: ```bash pnpm test:e2e ``` PRs are ready to ship only when `validate` and e2e both pass in that order. ## Domain Concepts | Entity | Location | Description | | --------- | -------------------- | ----------------------------------------------------------------------------------------------------- | | Skill | `~/.agents/skills/` | Directory with SKILL.md | | Agent | `~/.<agent>/skills/` | AI agents (count = `AGENT_DEFINITIONS.length` in `apps/desktop/src/shared/constants.ts`) | | Symlink | AgentβSkill | `valid` / `broken` / `inaccessible` / `missing` | | Universal | `~/.agents/skills/` | 19 agents share this source dir (see `UNIVERSAL_AGENT_IDS` in `apps/desktop/src/shared/constants.ts`) | ### Skills CLI | Resource | Location | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Repository | https://github.com/vercel-labs/skills (paths below are inside that repo) | | CLI agent list | `src/agents.ts` | | CLI types | `src/types.ts` | | Pinned version | `SKILLS_CLI_VERSION` in `apps/desktop/src/shared/constants.ts` (currently `1.7.0`) β bump when re-syncing `AGENT_DEFINITIONS` against the upstream skills CLI | `AGENT_DEFINITIONS` in `apps/desktop/src/shared/constants.ts` mirrors the CLI's agent list. Each entry: `id` (app state), `cliId` (`--agent` flag), `name` (display), `installDir` (home subpath where the CLI installs skills globally, like `.claude`), `scanDir` (home subpath this app scans for the agent's own symlinks; equals `installDir` except for universal-source agents where it diverges, e.g. Cline's `.cline`). ## UI Verification Drive the running app via **`playwright-cli`** (CDP attach to Electron's `:9222` debug port). The full workflow (phases, triage, report template) lives in the `/qa-electron` skill β invoke it for systematic QA runs. Quick ad-hoc verification commands: ```bash # 1. Start dev server (exposes CDP on :9222) pnpm dev # 2. Attach once per session playwright-cli attach --cdp=http://localhost:9222 # 3. Inspect + interact (use --s=default for the attached session) playwright-cli --s=default snapshot # a11y tree with eN element refs playwright-cli --s=default screenshot --filename=/tmp/shot.png playwright-cli --s=default click e5 # interact by ref from snapshot playwright-cli --s=default fill e3 "text" playwright-cli --s=default press Escape playwright-cli --s=default eval 'document.title' # run JS in renderer # 4. Detach when done (does NOT close the app β pnpm dev still owns it) playwright-cli --s=default detach ``` Re-snapshot after any action that mutates the DOM β `eN` refs are valid only for the most recent snapshot. ## QA Safety During QA runs, **do NOT delete skills under `~/.claude/skills/` or `~/.cursor/skills/`** β those are the user's live Claude Code and Cursor working sets. Skills under any other agent directory are safe to delete: they can be reinstalled instantly via the Marketplace tab or per-agent Cleanup. | Path | Deletable in QA? | Reason | | -------------------- | ---------------- | -------------------------------------------------- | | `~/.claude/skills/` | β | User's live Claude Code working set | | `~/.cursor/skills/` | β | User's live Cursor working set | | `~/.<other>/skills/` | β | Reinstallable via Marketplace or per-agent Cleanup | ### Adding a test skill for QA (global install) When a verification run needs a fresh, throwaway skill (e.g. to exercise the delete + UndoToast flow without touching anything the user actually relies on), install one globally in non-interactive mode: ```bash npx skills add --yes --global https://github.com/microsoft/azure-skills --skill azure-ai ``` `--yes` skips the skills CLI's confirmation prompts (scope, etc.); `--global` forces the install into `~/.agents/skills/` regardless of CWD (without it, running from inside a project with a local `.agents/` directory installs project-local instead). The new skill is symlinked into every installed agent immediately and is safe to delete in the same run. Use this in preference to deleting an existing user skill. ## Design Source `DESIGN.md` owns the app's visual system: product context, color roles, typography, spacing, radius, elevation, motion, component styling, accessibility, responsive behavior, and visual-polish guardrails. Keep design guidance there so agents and design tools have one place to read before changing UI. ## Design Review Principles When running `/design-review` (or any visual critique), apply two standing principles **in addition to** DESIGN.md compliance: ### 1. Benchmark against top-tier apps Don't grade UI only by "does it match DESIGN.md" β grade it against the bar set by best-in-class products: **Linear, Notion, Dia (The Browser Company), the Codex desktop app**, and peers (Warp, Raycast, VS Code). For every finding ask: _how would Linear / Notion / Dia / Codex handle this?_ Surface where the app falls short of that bar, not just where it breaks a written rule. The goal is parity with top-tier craft, not mere rule-compliance. ### 2. DESIGN.md is a living document β refine it, don't just obey it Using "DESIGN.md compliance" as the quality baseline only works if DESIGN.md actually encodes the rules needed for excellent UI/UX. It is almost certainly still incomplete. So a design review is **also an audit of DESIGN.md itself**: - When the top-tier benchmark (principle 1) surfaces a quality gap that DESIGN.md has no rule for, that gap is a **DESIGN.md deficiency**, not just a one-off fix. - Propose the missing rule and fold it into DESIGN.md so the next review inherits it. - Expanding/refining DESIGN.md is an expected, recurring part of the design-review workflow β not a separate task. DESIGN.md stays the binding visual source of truth; these two principles are how it earns and keeps that authority. ## Cursor Cloud specific instructions Cloud Agents run on Linux. `pnpm test`, `pnpm lint`, `pnpm typecheck`, `pnpm build`, and `pnpm --filter skills-desktop-website <script>` are the checks that run here. `pnpm test:e2e` and `pnpm build:mac` need macOS. - Node.js 24.20.0 and pnpm 11.5.1 are already on `PATH`. Prefer those over the image Node 22 at `/exec-daemon/node`. - Playwright Chromium is installed for Vitest browser mode. Reinstall with `pnpm --filter skills-desktop exec playwright install chromium --with-deps` only if the browser cache is missing. - Dev servers are not started on boot. Website: `pnpm --filter skills-desktop-website dev` (port 3000). Desktop: `pnpm dev` (CDP on port 9222). Electron needs `DISPLAY` and `XAUTHORITY` from the desktop session; a replaced `HOME` must still point `XAUTHORITY` at the session cookie. - `UNSPLASH_ACCESS_KEY` is optional. Without it, `POST /api/rpc/unsplash/search` returns `UNAVAILABLE` and built-in images still work. - `trashService.integration.test.ts` expects `ctime` to change on `rm` + `mkdir`. This VM's filesystem clock steps in 4ms ticks and ext4 reuses inode numbers, so those two same-path replacement tests can fail when the replacement stays inside one tick. That is host clock granularity.