{"owner":"elie222","repo":"inbox-zero","hasSkills":true,"totalSkillsCount":88,"totalTokensCount":31154,"categories":["anthropic-skill","root-instruction","claude-rule","codex-rule","plugin-manifest","subagent-persona","cursor-rule"],"hasMcp":false,"mcpConfig":null,"found":["clawhub/inbox-zero-api/SKILL.md",".claude/skills/ui-components/SKILL.md",".claude/skills/write-tests/SKILL.md",".claude/skills/wait/SKILL.md",".claude/skills/testing/SKILL.md",".claude/skills/review-ai-prompt-changes/SKILL.md",".claude/skills/update-packages/SKILL.md",".claude/skills/review/SKILL.md",".claude/skills/test-feature/SKILL.md",".claude/skills/qa-label/SKILL.md",".claude/skills/project-structure/SKILL.md",".claude/skills/prisma/SKILL.md",".claude/skills/logging/SKILL.md",".claude/skills/llm-test/SKILL.md",".claude/skills/llm/SKILL.md",".claude/skills/fullstack-workflow/SKILL.md",".claude/skills/explain-changes/SKILL.md",".claude/skills/environment-variables/SKILL.md",".claude/skills/e2e/SKILL.md",".claude/skills/create-pr/SKILL.md",".claude/skills/code-simplifier/SKILL.md",".claude/skills/cloud-dev-environment/SKILL.md",".claude/skills/changelog/SKILL.md",".claude/skills/agent-browser/SKILL.md","AGENTS.md","CLAUDE.md",".codex/config.toml",".cursor-plugin/plugin.json","agents/inbox-zero-api-cli.md",".claude/agents/reviewer.md",".codex/agents/code-simplifier.toml",".codex/agents/reviewer.toml",".cursor/rules/e2e-testing.mdc",".cursor/rules/posthog-feature-flags.mdc",".cursor/rules/task-list.mdc",".cursor/rules/ultracite.mdc","packages/tsconfig/base.json","packages/tsconfig/nextjs.json","packages/tsconfig/package.json","packages/tinybird-ai-analytics/package.json","packages/tinybird-ai-analytics/README.md","packages/tinybird-ai-analytics/tsconfig.json","packages/tinybird/package.json","packages/tinybird/README.md","packages/tinybird/tsconfig.json","packages/scheduling/package.json","packages/scheduling/tsconfig.json","packages/resend/package.json","packages/resend/README.md","packages/resend/tsconfig.json","packages/loops/package.json","packages/loops/README.md","packages/loops/tsconfig.json","packages/image-proxy/package.json","packages/image-proxy/tsconfig.json","packages/cli/package.json","packages/cli/README.md","packages/cli/tsconfig.json","packages/api/package.json","packages/api/README.md","packages/api/tsconfig.json",".claude/skills/testing/e2e.md",".claude/skills/testing/eval.md",".claude/skills/testing/integration.md",".claude/skills/testing/llm.md",".claude/skills/testing/unit.md",".claude/skills/testing/write-tests.md",".cursor/rules/features/cleaner.mdc",".cursor/rules/features/delayed-actions.mdc",".cursor/rules/features/digest.mdc",".cursor/rules/features/knowledge.mdc",".cursor/rules/features/reply-memory.mdc",".cursor/rules/features/schedule.mdc","clawhub/inbox-zero-api/references/cli-reference.md","clawhub/inbox-zero-api/agents/openai.yaml","packages/tinybird/project/tinybird.config.json",".claude/skills/review-ai-prompt-changes/agents/openai.yaml",".claude/skills/code-simplifier/agents/openai.yaml",".claude/skills/agent-browser/references/authentication.md",".claude/skills/agent-browser/references/commands.md",".claude/skills/agent-browser/references/profiling.md",".claude/skills/agent-browser/references/proxy-support.md",".claude/skills/agent-browser/references/session-management.md",".claude/skills/agent-browser/references/snapshot-refs.md",".claude/skills/agent-browser/references/video-recording.md",".claude/skills/agent-browser/templates/authenticated-session.sh",".claude/skills/agent-browser/templates/capture-workflow.sh",".claude/skills/agent-browser/templates/form-automation.sh"],"skills":{"clawhub/inbox-zero-api/SKILL.md":"---\nname: inbox-zero-api\ndescription: Use the Inbox Zero API CLI to inspect the live API schema, list and manage automation rules, and read inbox analytics through the public API. Use this when a task involves Inbox Zero rules, stats, or API-driven automation and can be solved through the CLI instead of browser interaction.\nhomepage: https://www.getinboxzero.com/api-reference/cli\nmetadata: { \"openclaw\": { \"skillKey\": \"inboxZeroApi\", \"requires\": { \"bins\": [\"inbox-zero-api\"], \"env\": [\"INBOX_ZERO_API_KEY\"] }, \"primaryEnv\": \"INBOX_ZERO_API_KEY\", \"install\": [ { \"id\": \"node\", \"kind\": \"node\", \"package\": \"@inbox-zero/api\", \"bins\": [\"inbox-zero-api\"], \"label\": \"Install Inbox Zero API CLI (npm)\" } ] } }\n---\n\n# Inbox Zero API CLI\n\nUse this skill when the task is to inspect or change Inbox Zero state through the public API.\n\n## Workflow\n\n1. Prefer `--json` so the output is stable and machine-readable.\n2. For authenticated commands (`rules`, `stats`, etc.), keep credentials in `INBOX_ZERO_API_KEY` or OpenClaw skill config. Avoid passing API keys as CLI flags unless there is no alternative.\n3. Before creating or replacing a rule body, fetch the live schema with `inbox-zero-api openapi --json` (no API key required).\n4. For create and update flows, write JSON into a workspace file or pipe it on stdin.\n5. Treat `rules update` as a full replacement. Read the current rule first if you only intend to change part of it.\n\n## Quick Start\n\n```bash\ninbox-zero-api rules list --json\ninbox-zero-api stats by-period --period week --json\ninbox-zero-api openapi --json\n```\n\nIf the CLI is not installed yet, install it with the OpenClaw installer or run `npm install -g @inbox-zero/api`.\n\n## Cursor\n\nSet `INBOX_ZERO_API_KEY` when using authenticated commands (`rules`, `stats`, etc.); `openapi --json` works without a key. Use shell profile, Cursor env, or a local env file—never commit keys. Install: `npm install -g @inbox-zero/api` or `npx @inbox-zero/api`.\n\n## OpenClaw Config\n\nSet the API key in `~/.openclaw/openclaw.json` under `skills.entries.inboxZeroApi.apiKey`, or export `INBOX_ZERO_API_KEY` in the host environment.\n\nUse `INBOX_ZERO_BASE_URL` or `inbox-zero-api config set base-url <url>` only for self-hosted or nonstandard deployments.\n\n## Reference\n\nFor exact command patterns and a safe mutation flow, read `references/cli-reference.md`.\n",".claude/skills/ui-components/SKILL.md":"---\nname: ui-components\ndescription: UI component and styling guidelines using Shadcn UI, Radix UI, and Tailwind\n---\n# UI Components and Styling\n\n## UI Framework\n- Use Shadcn UI and Tailwind for components and styling\n- Implement responsive design with Tailwind CSS using a mobile-first approach\n- Use `next/image` package for images\n\n## Install new Shadcn components\n\n```sh\npnpm dlx shadcn@latest add COMPONENT\n```\n\nExample:\n\n```sh\npnpm dlx shadcn@latest add progress\n```\n\n## Data Fetching with SWR\nFor API get requests to server use the `swr` package:\n\n```typescript\nconst searchParams = useSearchParams();\nconst page = searchParams.get(\"page\") || \"1\";\nconst { data, isLoading, error } = useSWR<PlanHistoryResponse>(\n  `/api/user/planned/history?page=${page}`\n);\n```\n\n## Loading Components\nUse the `LoadingContent` component to handle loading states:\n\n```tsx\n<Card>\n  <LoadingContent loading={isLoading} error={error}>\n    {data && <MyComponent data={data} />}\n  </LoadingContent>\n</Card>\n```\n\n## Form Components\n### Text Inputs\n```tsx\n<Input\n  type=\"email\"\n  name=\"email\"\n  label=\"Email\"\n  registerProps={register(\"email\", { required: true })}\n  error={errors.email}\n/>\n```\n\n### Text Area\n```tsx\n<Input\n  type=\"text\"\n  autosizeTextarea\n  rows={3}\n  name=\"message\"\n  placeholder=\"Paste in email content\"\n  registerProps={register(\"message\", { required: true })}\n  error={errors.message}\n/>\n```\n",".claude/skills/write-tests/SKILL.md":"---\nname: write-tests\ndescription: Write focused unit tests for backend and utility logic\ndisable-model-invocation: true\n---\nRead and follow `.claude/skills/testing/write-tests.md`.\n",".claude/skills/wait/SKILL.md":"---\nname: wait\ndescription: Pause execution for a user-specified duration\ndisable-model-invocation: true\n---\n\nwait X seconds/minutes (user will provide input). use `sleep` command. DONT do it in background\n",".claude/skills/testing/SKILL.md":"---\nname: testing\ndescription: Guidelines for testing the application with Vitest, including unit tests, integration tests (emulator), AI tests, and eval suites for LLM features\n---\n# Testing\n\nAll testing guidance lives in this directory. Read the relevant file for your task:\n\n| Type | File | When to use |\n|------|------|-------------|\n| Unit tests | [unit.md](unit.md) | Framework setup, mocks, colocated tests |\n| Writing tests | [write-tests.md](write-tests.md) | What to test, what to skip, workflow |\n| LLM tests | [llm.md](llm.md) | Tests that call real LLMs (`pnpm test-ai`) |\n| Eval suite | [eval.md](eval.md) | Cross-model comparison, LLM-as-judge |\n| Integration | [integration.md](integration.md) | Emulator-backed tests (`pnpm test-integration`) |\n| Database | `apps/web/__tests__/db/README.md` | Real Postgres, for unique constraints and `updateMany` count guards (`pnpm test-db`) |\n| E2E tests | [e2e.md](e2e.md) | Real email workflow tests from inbox-zero-e2e repo |\n\nPrefer behavior-focused assertions; avoid freezing prompt copy or internal call shapes unless those exact values are the contract under test.\n\n## Quick Commands\n\n```bash\npnpm test path/to/file.test.ts       # Single unit test\npnpm test                            # All unit tests\npnpm test-integration                # Integration tests (emulator)\npnpm test-db                         # Database tests (needs DATABASE_URL on a throwaway db)\npnpm test-ai ai-regression/your-feature  # Live AI regression test\nEVAL_MODELS=all pnpm test-ai eval/your-feature  # Eval across models\n```\n",".claude/skills/review-ai-prompt-changes/SKILL.md":"---\nname: review-ai-prompt-changes\ndescription: Review prompt and tool-description changes in a branch or PR. Use when asked to audit system prompts, prompt builders, tool descriptions, prompt inputs, or nearby evals/tests; summarize what changed; identify guidance that feels eval-shaped or too heavy for product use; and find repeated instructions between the main prompt and tool descriptions.\n---\n\n# Review Prompt Changes\n\nReview prompt-related diffs with a product lens. Focus on what actually changed, whether the guidance belongs in the prompt layer where it was added, and whether any wording is repetitive or overfit to evals.\n\n## Scope\n\n- Default to `main...HEAD` unless the user names a different base.\n- Prioritize runtime files that shape model behavior:\n  - system prompts\n  - prompt builders and prompt fragments\n  - tool descriptions and schema field descriptions\n  - response-formatting instructions\n- Read evals and unit tests only after the runtime diffs so you can infer the intent behind the change without letting the tests define the review.\n\nIn this repo, likely files live under:\n\n- `apps/web/utils/ai/**`\n- `apps/web/utils/ai/assistant/**`\n- `apps/web/__tests__/eval/**`\n- `apps/web/__tests__/**` for prompt-adjacent unit tests\n\n## Workflow\n\n1. Find the changed files with `git diff --name-only main...HEAD`.\n2. Narrow to prompt-relevant files first. Ignore unrelated UI or plumbing unless it changes what reaches the model.\n3. Read diffs with enough context to see the full prompt block or tool description.\n4. Then read nearby tests or evals to understand what failure mode the change is trying to prevent.\n5. Separate your notes into four buckets:\n   - behavior changes\n   - product-helpful prompt guidance\n   - heavy or eval-shaped guidance\n   - repeated guidance across layers\n6. Prefer exact file and line references in the review.\n\n## What To Look For\n\n### Product-helpful changes\n\n- Capability gating that matches real product states or disabled tools\n- Moving provider-specific or tool-specific guidance into the relevant tool description\n- Adding richer tool outputs that support grounded answers\n- Clear write-confirmation or safety rules tied to real UI behavior\n\n### Heavy or eval-shaped changes\n\n- Cross-cutting language added mainly to defend a known eval failure mode\n- Response-policy coaching inside a tool description when it is not tool-local\n- Repeated “treat as evidence,” “state the conflict plainly,” or “do not invent causes” language across multiple prompt layers\n- Tiny wording splits that duplicate long blocks for web vs messaging, provider A vs provider B, or enabled vs disabled states\n- Instructions that read like judging criteria instead of operating guidance\n\n### Repetition to call out\n\nCheck whether the same instruction appears in more than one of these places:\n\n- the system prompt\n- tool descriptions\n- input schema field descriptions\n- formatting blocks\n- tests or eval-driven comments copied into runtime prompt text\n\nTool-local guidance usually belongs in the tool description. Cross-cutting behavior rules usually belong in the main prompt. Flag cases where both layers say the same thing without adding meaning.\n\n## Review Output\n\nUse this structure:\n\n1. `Findings`\n   - findings first, ordered by severity\n   - include file and line references\n   - focus on heaviness, redundancy, or misplaced guidance\n2. `What Changed`\n   - summarize the actual prompt/tool behavior changes\n   - mention tests or evals only as evidence of intent\n3. `Net Read`\n   - say which changes feel product-helpful\n   - say which changes feel eval-shaped\n   - say what the best trim targets are\n\nKeep the review concise, but cover the full prompt story. The user asked for both the diff summary and the judgment call.\n\n## Repo Notes\n\n- Project-specific skills live under `.claude/skills/<skill-name>/SKILL.md`.\n- Match the house style: short frontmatter, concise body, no extra README files.\n- Do not edit prompts by default. This skill is for audit/review unless the user explicitly asks for changes.\n",".claude/skills/update-packages/SKILL.md":"---\nname: update-packages\ndescription: Update workspace packages while respecting the repo's pinned package list in .ncurc.cjs. Use when the user asks to update dependencies or refresh package versions.\n---\n\n# Update Packages\n\nUse this workflow when updating dependencies in this repo.\n\n## Steps\n\n1. Check the pinned package list in `.ncurc.cjs`. Do not upgrade packages listed there.\n2. Keep the repo on Node 24. If you change Node runtime settings, update `.nvmrc`, `engines.node`, `@types/node`, Dockerfiles, and CI together.\n3. Update manifests across the workspace:\n\n```sh\npnpm dlx npm-check-updates -u -ws\n```\n\n4. Refresh the lockfile and install updated packages:\n\n```sh\npnpm install\n```\n\n5. Verify the update:\n\n```sh\npnpm test\npnpm lint\n```\n\n## Notes\n\n- Pin registry `dependencies`, `devDependencies`, and `optionalDependencies` to exact versions. Preserve supported `peerDependencies` ranges in public packages: peers describe consumer compatibility, not lockfile reproducibility. For example, keep the email editor's React and React DOM peers at `>=19` unless its actual compatibility requirements change.\n- `npm-check-updates` reads `.ncurc.cjs`, so the reject list is applied during the manifest update.\n- `pnpm install` may also bump the root `packageManager` field and regenerate `pnpm-lock.yaml`.\n- Do not run `pnpm dev` or `pnpm build` unless the user explicitly asks.\n- Keep `@hookform/resolvers` in the `.ncurc.cjs` reject list and pinned to `4.1.0` while `apps/web` remains on `zod@3.25.76`. The `5.x` resolver line imports `zod/v4/core`, which has caused local Next.js/Turbopack resolution failures even though the app code still uses Zod 3.\n",".claude/skills/review/SKILL.md":"---\nname: review\ndescription: Review code changes, auto-fix safe issues, and report bugs\ndisable-model-invocation: true\n---\n\n# review\n\nCode review with craftsman's eye. Auto-fix obvious issues, surface real bugs.\n\nReference @AGENTS.md for project conventions. Apply those patterns as review criteria.\n\n## Critical Rules\n\n1. **AUTO-FIX safe obvious issues** - Don't ask permission for no-brainers\n2. **HUNT FOR BUGS** - Logic errors, edge cases, race conditions first\n3. **WAIT for confirmation** - On BUG/FIX, don't execute until user says \"go\"\n4. **BE CONCISE** - One-line items, choices at END\n5. **USE clickable links** - `path/to/file.ts:123` format only\n\n## Categories\n\n| Category | What | Action |\n|----------|------|--------|\n| **[BUG]** | Logic errors, security, data loss, race conditions | Report → wait |\n| **[FIX]** | Type gaps, missing error handling, test gaps, slop | Report → wait |\n| **[AUTO]** | Unused imports, dead code, console.log, typos | Fix immediately |\n| **[CONSIDER]** | Refactors, style opinions, nice-to-have | Mention only |\n\n### AUTO Criteria (all must be true)\n\n- Zero risk of breaking behavior\n- <5 seconds to fix\n- No judgment call needed\n\n**AUTO examples:**\n- Unused imports/variables\n- Trailing whitespace\n- Console.log (unless intentional)\n- Dead/unreachable code\n- Obvious typos in comments/strings\n\n**NOT AUTO (needs confirmation):**\n- Removing \"unused\" function (might be used elsewhere)\n- Type changes (might change behavior)\n- Any logic change\n- AI slop removal (might be intentional)\n\n## Project-Specific Checks\n\n**Always ask these questions during review:**\n\n### Can this be simpler?\n- Is there unnecessary abstraction? Could this be done with less code?\n- Are there helpers/utils being created for one-time operations?\n- Over-engineered error handling, feature flags, or backwards-compat shims?\n- Unnecessary wrapper components or HOCs?\n\n### Can we remove any code?\n- Dead code, unused exports, commented-out blocks?\n- Re-exports or barrel files (we don't use barrel files)?\n- Backwards-compatibility hacks like renamed `_vars` or `// removed` comments?\n- Types/interfaces exported but only used in the same file?\n\n### Is it DRY without premature abstraction?\n- Obvious copy-paste of entire functions or large blocks → refactor\n- But 2-3 similar lines are fine — don't abstract too early\n- The wrong abstraction is worse than duplication\n\n### Is it structured correctly?\n- **Colocate page-specific components** next to their page (not in a nested `components/` subfolder — we don't do that in route directories)\n- **General/reusable components** go in `apps/web/components/`\n- **API routes**: One resource per route, not combined data endpoints\n- **Server actions** for mutations, not POST routes\n- **Validation schemas** in separate `.validation.ts` files\n- **Helper functions** at the bottom of files, not the top\n- **All imports** at the top — no mid-file dynamic imports\n- **No barrel files** (index.ts re-exporting everything from a folder)\n\n### Does it follow project patterns? (see @AGENTS.md)\n- GET routes wrapped with `withAuth` or `withEmailAccount`?\n- Response types exported as `Awaited<ReturnType<typeof fn>>`?\n- SWR for client-side data fetching?\n- `LoadingContent` for loading/error states?\n- `useAction` from `next-safe-action/hooks` for form submissions?\n- Zod schemas with `z.infer<typeof schema>` instead of duplicate interfaces?\n- Self-documenting code? Comments explain \"why\" not \"what\"?\n- `logger.trace()` for PII fields?\n- Test changes follow `.claude/skills/testing/SKILL.md`?\n- Tests avoid mocking `@/utils/logger`?\n- If draft-generation prompt, retrieval, routing, or post-processing changed, was `apps/web/utils/ai/reply/draft-attribution.ts` `DRAFT_PIPELINE_VERSION` bumped for analytics?\n\n### Learnings check\n- Did this change teach us something that should be captured in `AGENTS.md` or this review file?\n- Are there patterns that keep coming up that we should document?\n\n## Mindset\n\n**Inheritance Test:** Would I curse the previous author? Understand at 2am?\n\n**Pride Test:** Would I put my name on this?\n\n## Workflow\n\n### Step 0: Determine Scope & Group Files\n\nAuto-detect: conversation changes → staged → current diff\n\n```bash\ngit diff --cached --name-only  # or HEAD\n```\n\n**Group files by area/dependency:**\n```\nBatch 1: apps/web/app/api/agent/* (3 files)\nBatch 2: apps/web/app/(app)/[emailAccountId]/agent/* (related components)\nBatch 3: apps/web/utils/actions/* (2 files)\n```\n\n**Output:** `Found X files in Y batches`\n\n──────────\n\n### Step 1: Create Review Plan (TODO)\n\n**BEFORE reading any file content**, create todo list:\n\n```\n- [ ] Batch 1: API routes (skills, allowed-actions)\n- [ ] Batch 2: agent page components (agent-page, chat, tools)\n- [ ] Batch 3: server actions (agent.ts, agent.validation.ts)\n```\n\nUse `todo_write` to track batches.\n\n──────────\n\n### Step 2: Process Each Batch\n\n**For each batch:**\n\n1. Read diff for batch files only (`git diff --cached -- path/to/files`)\n2. Review & categorize issues\n3. Auto-fix [AUTO] items immediately\n4. Note [BUG]/[FIX]/[CONSIDER] items\n5. Mark batch complete in todos\n\n**Issue format:**\n```\n1. **[BUG]** Race condition in concurrent saves — `src/db.ts:45`\n2. **[FIX]** Missing error boundary — `src/App.tsx:12`\n3. **[CONSIDER]** Extract to custom hook — `src/Form.tsx:34`\n```\n\n**After each batch:**\n```\nBatch 1 done: AUTO: 2 fixed | BUG: 1 | FIX: 2\n```\n\n──────────\n\n### Step 3: Summary & Options (After All Batches)\n\n```\nTotal: BUG: X | FIX: X | CONSIDER: X (auto-fixed: Y)\n\nIssues:\n1. [BUG] ... — `path:line`\n2. [FIX] ... — `path:line`\n\nWhat to fix?\n- a) BUG + FIX [recommended]\n- b) BUG only\n- c) All including CONSIDER\n- d) Custom (e.g., \"1,3\")\n\nI'll assume a) if you don't specify.\n\nLearnings:\n- Any patterns worth adding to AGENTS.md?\n- Any new review checks to add to this file?\n```\n\n**STOP. Wait for selection.**\n\n──────────\n\n### Step 4: Execute Fixes\n\nProcess fixes batch-by-batch (same grouping):\n\n1. Update todo list with selected fixes\n2. For each batch:\n   - Read relevant file(s)\n   - Apply fixes\n   - Mark complete\n3. Run linter if applicable\n\n## Severity Guide\n\n**BUG (Logic/Security):**\n- Business logic errors, wrong conditions\n- Race conditions, data loss\n- Security: injection, XSS, exposed secrets\n- API routes missing auth middleware\n- Null/undefined not handled\n- Edge cases that break\n\n**FIX (Quality):**\n- Type safety gaps, unsafe casts\n- Missing error handling\n- Test coverage gaps\n- AI slop (WHAT comments, unnecessary try/catch, `as any`)\n- Missing validation\n- Combined API routes that should be separate\n- POST routes used for mutations instead of server actions\n- Barrel files / re-export patterns\n\n**CONSIDER (Opinions):**\n- Refactoring opportunities\n- \"I would do it differently\"\n- Performance micro-optimizations\n- Style preferences\n\n## Git Commands\n\n```bash\n# Staged\ngit diff --cached\ngit diff --cached --name-only\n\n# All uncommitted\ngit diff HEAD\ngit diff HEAD --name-only\n```\n\n## Error Handling\n\n| Error | Response |\n|-------|----------|\n| No changes | \"Check git status or specify files\" |\n| File not found | List available, ask to specify |\n| Binary files | Skip, mention in summary |\n| Large file (>10k) | \"Review specific sections?\" |\n",".claude/skills/test-feature/SKILL.md":"---\nname: test-feature\ndescription: \"End-to-end feature testing — browser QA, API verification, eval tests, or any combination. Covers browser interactions (via agent-browser CLI), Google Workspace operations (gws CLI), API calls, and LLM eval tests. Can also persist checks as reusable automated tests.\"\ndisable-model-invocation: true\nargument-hint: \"<description of feature to test>\"\n---\n\nArgs: $ARGUMENTS\n\nYou are an end-to-end feature tester for Inbox Zero. Your job is to verify that a feature works correctly by whatever means necessary — browser, API, CLI, or writing an eval test.\n\n## When invoked\n\nThe user will describe a feature to test, or you can infer it from recent code changes. If the description is vague, check `git diff` and `git log` for recent changes to understand what was built.\n\nThe user may point you to an existing worktree, branch, or PR to test against. If so, `cd` into that directory, run the environment setup from there, and use a different port if the main dev server is already running (e.g., `PORT=3001 pnpm dev`).\n\n## Step 0: Environment setup\n\nBefore testing, make sure the local environment is ready. These steps are idempotent — skip any that are already done.\n\n1. **Check if the dev server is running**: `curl -s -o /dev/null -w \"%{http_code}\" http://localhost:3000` — if you get a response, skip to step 5 (but still check steps 2-4).\n2. **Ensure `.env` exists**: If `apps/web/.env` is missing (common in worktrees), try symlinking from a shared location:\n   ```bash\n   ln -sf ~/.inbox-zero/.env apps/web/.env\n   ln -sf ~/.inbox-zero/.env.test apps/web/.env.test  # for eval tests\n   ```\n   If those symlink sources don't exist, ask the user where their env file is.\n3. **Enable required feature flags**: Check `.env.example` for any env vars the feature needs (e.g. `NEXT_PUBLIC_EXTERNAL_API_ENABLED=true`). If any are missing from `apps/web/.env`, add them now. **IMPORTANT**: `NEXT_PUBLIC_*` vars are baked in at build time — if you add one to `.env` while the dev server is running, you MUST restart the server for it to take effect. Do this BEFORE testing, not after. Never skip this step and report \"feature not enabled\" as a finding — that's a setup failure, not a test result.\n4. **Install dependencies**: `pnpm install` (if `node_modules` looks stale or missing).\n5. **Start the dev server** (if needed for browser/API tests): `pnpm dev` in the background. Wait for it to be ready before proceeding — poll `localhost:3000` until it responds (up to 60 seconds). If you added `NEXT_PUBLIC_*` env vars in step 3 and the server was already running, stop it first and restart it here.\n\n### Isolated local browser QA\n\nFor focused visual QA, check for a free port and initialize an isolated environment:\n\n```bash\npnpm dev-setup init --db empty --auth emulate --url localhost --port <port>\npnpm dev-setup dev --skip-init\n```\n\n- Include `--skip-init` on every subsequent `dev-setup dev` or `dev-setup exec` command; omitting it resets the isolated database.\n- Set required feature flags when starting the server, for example `NEXT_PUBLIC_DIGEST_ENABLED=true pnpm dev-setup dev --skip-init`.\n- Run `pnpm install` if `apps/web/node_modules/@inboxzero/*` links point outside the repository or to a deleted checkout.\n- Seed only the state needed for the test and mark onboarding complete to avoid unrelated setup work. Keep temporary auth and seed files under `.context/` and remove them afterward.\n\n## Step 1: Plan the test\n\nBefore doing anything, decide the right testing approach. Often you'll combine multiple:\n\n| What you're testing | Approach |\n|---|---|\n| UI behavior, settings pages, visual changes | Browser QA — interact with the app, take screenshots |\n| Google Workspace integrations (Drive, Calendar, Gmail) | `gws` CLI for data setup + browser for verification |\n| API endpoints | Direct HTTP calls (curl/fetch), possibly via the app's API with an API key |\n| AI/LLM output quality (drafts, categorization, rules) | Eval test — write or run a test in `__tests__/eval/` |\n| Email processing workflows | E2E flow test or browser QA depending on scope |\n\nTell the user your plan in 2-3 sentences before executing. If you need access or credentials you don't have, say so upfront.\n\n## Step 2: Set up test data\n\nCreate whatever test data the feature needs. Examples:\n- **Google Drive**: Use `gws drive files create` to make folders/files, or do it in the browser\n- **Gmail**: Use `gws gmail users messages send` or send a test email through the browser\n- **Calendar**: Use `gws calendar events insert` to create test events\n- **App config**: Use the browser to configure settings (rules, writing style, connected accounts, etc.)\n\nWhen using `gws`, prefer it for data setup since it's faster and more reliable than browser clicks for creating files/folders/events. Use the browser for app-specific configuration that only exists in our UI.\n\n## Step 3: Execute the test\n\n### Browser testing (via `agent-browser` CLI)\nUse the `agent-browser` skill for all browser interactions. The core loop is: open → snapshot → interact → re-snapshot → screenshot.\n\n- **Navigate by direct URL**: `agent-browser click` on sidebar links can be unreliable. Prefer `agent-browser --cdp 9222 open <full-url>`.\n- **Set viewport to 1440x900**: Headless Chrome defaults to a tiny viewport. After connecting, set it via CDP:\n  ```bash\n  TARGET_ID=$(curl -s http://127.0.0.1:9222/json | node -p \"JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).find(t=>t.type==='page'&&!t.url.startsWith('chrome')).id\")\n  node -e \"const d=JSON.stringify({id:1,method:'Emulation.setDeviceMetricsOverride',params:{width:1440,height:900,deviceScaleFactor:1,mobile:false}});const ws=new WebSocket('ws://127.0.0.1:9222/devtools/page/$TARGET_ID');ws.onopen=()=>ws.send(d);ws.onmessage=()=>ws.close();\"\n  ```\n\n#### Interacting with the chat input\nThe chat textarea has `data-testid=\"chat-input\"`. Use:\n```bash\nagent-browser fill \"[data-testid=chat-input]\" \"Your message here\"\nagent-browser press Enter                          # submit\nsleep 15-30                                        # wait for AI response\nagent-browser screenshot /tmp/result.png\n```\nKey: `fill` and `type` require a **selector** as the first arg (CSS selector or `@ref`). Never call `type \"some text\"` without a selector — that's `keyboard type` (different command). When a CSS selector matches multiple elements, use `agent-browser snapshot` to get unique `@ref` identifiers.\n- Navigate the app as a user would\n- Take a screenshot at every meaningful step — the user wants to see what the UI looks like\n- Pay special attention to: loading states, error states, empty states, success confirmations\n- If testing a flow (e.g., email → rule → draft), wait for async operations to complete before checking results\n- Always `agent-browser close` when done to clean up\n\n#### App route reference\n- Assistant chat: `/<emailAccountId>/assistant`\n- Assistant rules: `/<emailAccountId>/automation`\n- Assistant settings: `/<emailAccountId>/automation?tab=settings`\n- Bulk unsubscribe: `/<emailAccountId>/bulk-unsubscribe`\n- Settings: `/settings`\n\n#### Browser authentication\n\nThe app requires OAuth login. agent-browser can't complete OAuth, so you need a Chrome profile with an existing logged-in session.\n\n**Preferred approach: headless Chrome with a saved profile**\n\nThe user should have a dedicated Chrome profile directory with a logged-in session (stored outside the repo, e.g. `~/.chrome-debug-inbox-zero`). Check the user's auto-memory for the profile path. Then launch Chrome headless and connect:\n\n```bash\n# 1. Check if CDP is already running\ncurl -s http://127.0.0.1:9222/json/version\n\n# 2. If not, launch Chrome headless with the saved profile\n\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\" \\\n  --headless=new \\\n  --remote-debugging-port=9222 \\\n  --user-data-dir=\"$HOME/.chrome-debug-<name>\" &>/dev/null &\nsleep 3\n\n# 3. Connect agent-browser\nagent-browser close\ncurl -s -X PUT \"http://127.0.0.1:9222/json/new?about:blank\" > /dev/null\nsleep 2\nagent-browser --cdp 9222 open http://localhost:3000/automation\n```\n\nThis runs entirely in the background — the user doesn't need to do anything.\n\n**Important caveats:**\n- Chrome won't allow two instances with the same `--user-data-dir` — kill any existing debug Chrome before launching.\n- If auth cookies have expired, the user needs to launch Chrome **headed** (without `--headless=new`) once to re-login via OAuth, then you can go back to headless.\n- Google OAuth blocks agent-browser's built-in Chromium (\"This browser or app may not be secure\") — must use real Chrome.\n- `agent-browser` may attach to `chrome://` internal pages — close those via `agent-browser close` before connecting.\n\n**Fallback options:**\n1. **Connect to user's running Chrome via CDP**: If the user already has Chrome open with `--remote-debugging-port=9222`, just use `agent-browser --cdp 9222`.\n2. **Headed mode with profile**: Use `agent-browser --headed --profile <path>` to open a visible Chrome window.\n3. **State file**: After signing in, save with `agent-browser state save ./auth.json` and reload later with `agent-browser --state ./auth.json`. Note: state files can expire.\n\n### API testing\n- Get a real API key from the UI first (Settings → API Keys) — screenshot the process. **Do not test with fake or dummy API keys**; auth errors mask whether the actual feature works.\n- Configure the CLI/client with the real key, then make real API calls and verify the responses show the expected data.\n- Check both success and error cases.\n\n### Eval testing\n- If the right approach is an eval test, check `__tests__/eval/` for existing tests that cover similar ground\n- Follow the eval test template in `.claude/skills/testing/eval.md`\n- Use `describeEvalMatrix` for cross-model comparison when relevant\n- Use `judgeMultiple` with appropriate `CRITERIA` for subjective outputs\n- Run with `pnpm test-ai eval/<test-name>`\n\n### Hybrid approaches\nOften the best test combines approaches. For example:\n- Use `gws` to create a Google Drive folder with a test PDF\n- Use the browser to configure the feature to use that folder\n- Trigger the feature (send an email, start a chat, etc.)\n- Verify the result in both the UI (screenshot) and via API/database\n\n## Step 4: Report results\n\n**An error means the test failed.** Do not report success if any step produced an error, even if the error seems like a configuration issue. Either fix the configuration and retry, or report the failure clearly.\n\nGive a clear pass/fail summary:\n- What was tested\n- What worked\n- What failed — with screenshots and the actual error\n- What you did to try to fix it\n\nAlways include screenshots — even for passing tests. The user wants to see what the UI looks like.\n\n## Step 5: Persist (if appropriate)\n\nAfter testing, ask the user if this should become a reusable test. Choose the\nsmallest automated boundary that exercises the behavior:\n\n1. **Emulated Playwright test** — for deterministic browser behavior that can\n   run without third-party credentials. Add it under\n   `apps/web/__tests__/playwright/emulated/<area>/` and follow\n   `apps/web/__tests__/playwright/README.md` and the existing fixture patterns.\n\n2. **Real-provider E2E flow** — for Gmail or Outlook delivery, webhooks,\n   provider labels, drafts, or other production-path behavior. Add it under\n   `apps/web/__tests__/e2e/flows/` without replacing provider operations with\n   emulator or database shortcuts.\n\n3. **Eval test** — if the test is about AI output quality, write a proper eval\n   test in `apps/web/__tests__/eval/` that can be run with `pnpm test-ai`.\n\nDon't persist trivial one-off checks (like \"does this page load\"). Persist tests that verify important behavior someone might break later.\n\n## Tool reference\n\n### gws CLI (Google Workspace)\n```bash\n# Create a Drive folder\ngws drive files create --json '{\"name\": \"Test Folder\", \"mimeType\": \"application/vnd.google-apps.folder\"}'\n\n# Upload a file to a folder\ngws drive files create --json '{\"name\": \"test.pdf\", \"parents\": [\"FOLDER_ID\"]}' --upload ./test.pdf\n\n# List Drive files\ngws drive files list --params '{\"q\": \"name contains '\\''test'\\''\", \"pageSize\": 10}'\n\n# Send a Gmail message\ngws gmail users messages send --params '{\"userId\": \"me\"}' --json '{\"raw\": \"BASE64_ENCODED_MESSAGE\"}'\n\n# Create a calendar event\ngws calendar events insert --params '{\"calendarId\": \"primary\"}' --json '{\"summary\": \"Test Event\", \"start\": {\"dateTime\": \"...\"}, \"end\": {\"dateTime\": \"...\"}}'\n```\n\n### Eval test utilities\n- `describeEvalMatrix(name, fn)` — run across models\n- `createEvalReporter()` — track pass/fail\n- `judgeMultiple({ input, output, criteria })` — LLM-as-judge\n- `CRITERIA.*` — ACCURACY, COMPLETENESS, TONE, CONCISENESS, NO_HALLUCINATION, CORRECT_FORMAT\n\n### Existing QA infrastructure\n- Emulated browser tests: `apps/web/__tests__/playwright/emulated/`\n- Real-provider E2E tests: `apps/web/__tests__/e2e/flows/`\n- Eval tests: `apps/web/__tests__/eval/`\n",".claude/skills/qa-label/SKILL.md":"---\nname: qa-label\ndescription: Label a PR as ready for QA so the QA server picks it up automatically\n---\n\nTo mark a PR ready for QA, run: `gh pr edit <PR_NUMBER> --add-label \"ready-for-qa\"`\n\nAn automated QA process on the QA server will pick it up within ~60s and run browser tests against the PR branch. New pushes retrigger automatically while the label is present.\n",".claude/skills/project-structure/SKILL.md":"# project-structure\n\nPath: `.claude/skills/project-structure/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/project-structure/SKILL.md)",".claude/skills/prisma/SKILL.md":"# prisma\n\nPath: `.claude/skills/prisma/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/prisma/SKILL.md)",".claude/skills/logging/SKILL.md":"# logging\n\nPath: `.claude/skills/logging/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/logging/SKILL.md)",".claude/skills/llm-test/SKILL.md":"# llm-test\n\nPath: `.claude/skills/llm-test/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/llm-test/SKILL.md)",".claude/skills/llm/SKILL.md":"# llm\n\nPath: `.claude/skills/llm/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/llm/SKILL.md)",".claude/skills/fullstack-workflow/SKILL.md":"# fullstack-workflow\n\nPath: `.claude/skills/fullstack-workflow/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/fullstack-workflow/SKILL.md)",".claude/skills/explain-changes/SKILL.md":"# explain-changes\n\nPath: `.claude/skills/explain-changes/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/explain-changes/SKILL.md)",".claude/skills/environment-variables/SKILL.md":"# environment-variables\n\nPath: `.claude/skills/environment-variables/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/environment-variables/SKILL.md)",".claude/skills/e2e/SKILL.md":"# e2e\n\nPath: `.claude/skills/e2e/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/e2e/SKILL.md)",".claude/skills/create-pr/SKILL.md":"# create-pr\n\nPath: `.claude/skills/create-pr/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/create-pr/SKILL.md)",".claude/skills/code-simplifier/SKILL.md":"# code-simplifier\n\nPath: `.claude/skills/code-simplifier/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/code-simplifier/SKILL.md)",".claude/skills/cloud-dev-environment/SKILL.md":"# cloud-dev-environment\n\nPath: `.claude/skills/cloud-dev-environment/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/cloud-dev-environment/SKILL.md)",".claude/skills/changelog/SKILL.md":"# changelog\n\nPath: `.claude/skills/changelog/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/changelog/SKILL.md)",".claude/skills/agent-browser/SKILL.md":"# agent-browser\n\nPath: `.claude/skills/agent-browser/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/SKILL.md)","AGENTS.md":"# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/AGENTS.md)","CLAUDE.md":"# Claude Agent Guidelines & System Prompt\n\nPath: `CLAUDE.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/CLAUDE.md)",".codex/config.toml":"# Codex Directive: config.toml\n\nPath: `.codex/config.toml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/config.toml)",".cursor-plugin/plugin.json":"# cursor-plugin Plugin Manifest\n\nPath: `.cursor-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor-plugin/plugin.json)","agents/inbox-zero-api-cli.md":"# Subagent: inbox-zero-api-cli\n\nPath: `agents/inbox-zero-api-cli.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/agents/inbox-zero-api-cli.md)",".claude/agents/reviewer.md":"# Subagent: reviewer\n\nPath: `.claude/agents/reviewer.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/agents/reviewer.md)",".codex/agents/code-simplifier.toml":"# Codex Directive: code-simplifier.toml\n\nPath: `.codex/agents/code-simplifier.toml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/agents/code-simplifier.toml)",".codex/agents/reviewer.toml":"# Codex Directive: reviewer.toml\n\nPath: `.codex/agents/reviewer.toml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/agents/reviewer.toml)",".cursor/rules/e2e-testing.mdc":"# Cursor Rule: e2e-testing\n\nPath: `.cursor/rules/e2e-testing.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/e2e-testing.mdc)",".cursor/rules/posthog-feature-flags.mdc":"# Cursor Rule: posthog-feature-flags\n\nPath: `.cursor/rules/posthog-feature-flags.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/posthog-feature-flags.mdc)",".cursor/rules/task-list.mdc":"# Cursor Rule: task-list\n\nPath: `.cursor/rules/task-list.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/task-list.mdc)",".cursor/rules/ultracite.mdc":"# Cursor Rule: ultracite\n\nPath: `.cursor/rules/ultracite.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/ultracite.mdc)","packages/tsconfig/base.json":"# Tsconfig Skill\n\nPath: `packages/tsconfig/base.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/base.json)","packages/tsconfig/nextjs.json":"# Tsconfig Skill\n\nPath: `packages/tsconfig/nextjs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/nextjs.json)","packages/tsconfig/package.json":"# Tsconfig Skill\n\nPath: `packages/tsconfig/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/package.json)","packages/tinybird-ai-analytics/package.json":"# Tinybird-ai-analytics Skill\n\nPath: `packages/tinybird-ai-analytics/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/package.json)","packages/tinybird-ai-analytics/README.md":"# tinybird-ai-analytics Documentation\n\nPath: `packages/tinybird-ai-analytics/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/README.md)","packages/tinybird-ai-analytics/tsconfig.json":"# Tinybird-ai-analytics Skill\n\nPath: `packages/tinybird-ai-analytics/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/tsconfig.json)","packages/tinybird/package.json":"# Tinybird Skill\n\nPath: `packages/tinybird/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/package.json)","packages/tinybird/README.md":"# tinybird Documentation\n\nPath: `packages/tinybird/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/README.md)","packages/tinybird/tsconfig.json":"# Tinybird Skill\n\nPath: `packages/tinybird/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/tsconfig.json)","packages/scheduling/package.json":"# Scheduling Skill\n\nPath: `packages/scheduling/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/scheduling/package.json)","packages/scheduling/tsconfig.json":"# Scheduling Skill\n\nPath: `packages/scheduling/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/scheduling/tsconfig.json)","packages/resend/package.json":"# Resend Skill\n\nPath: `packages/resend/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/package.json)","packages/resend/README.md":"# resend Documentation\n\nPath: `packages/resend/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/README.md)","packages/resend/tsconfig.json":"# Resend Skill\n\nPath: `packages/resend/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/tsconfig.json)","packages/loops/package.json":"# Loops Skill\n\nPath: `packages/loops/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/package.json)","packages/loops/README.md":"# loops Documentation\n\nPath: `packages/loops/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/README.md)","packages/loops/tsconfig.json":"# Loops Skill\n\nPath: `packages/loops/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/tsconfig.json)","packages/image-proxy/package.json":"# Image-proxy Skill\n\nPath: `packages/image-proxy/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/image-proxy/package.json)","packages/image-proxy/tsconfig.json":"# Image-proxy Skill\n\nPath: `packages/image-proxy/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/image-proxy/tsconfig.json)","packages/cli/package.json":"# Cli Skill\n\nPath: `packages/cli/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/package.json)","packages/cli/README.md":"# cli Documentation\n\nPath: `packages/cli/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/README.md)","packages/cli/tsconfig.json":"# Cli Skill\n\nPath: `packages/cli/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/tsconfig.json)","packages/api/package.json":"# Api Skill\n\nPath: `packages/api/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/package.json)","packages/api/README.md":"# api Documentation\n\nPath: `packages/api/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/README.md)","packages/api/tsconfig.json":"# Api Skill\n\nPath: `packages/api/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/tsconfig.json)",".claude/skills/testing/e2e.md":"# Testing Skill\n\nPath: `.claude/skills/testing/e2e.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/e2e.md)",".claude/skills/testing/eval.md":"# Testing Skill\n\nPath: `.claude/skills/testing/eval.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/eval.md)",".claude/skills/testing/integration.md":"# Testing Skill\n\nPath: `.claude/skills/testing/integration.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/integration.md)",".claude/skills/testing/llm.md":"# Testing Skill\n\nPath: `.claude/skills/testing/llm.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/llm.md)",".claude/skills/testing/unit.md":"# Testing Skill\n\nPath: `.claude/skills/testing/unit.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/unit.md)",".claude/skills/testing/write-tests.md":"# Testing Skill\n\nPath: `.claude/skills/testing/write-tests.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/write-tests.md)",".cursor/rules/features/cleaner.mdc":"# Cursor Rule: cleaner\n\nPath: `.cursor/rules/features/cleaner.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/cleaner.mdc)",".cursor/rules/features/delayed-actions.mdc":"# Cursor Rule: delayed-actions\n\nPath: `.cursor/rules/features/delayed-actions.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/delayed-actions.mdc)",".cursor/rules/features/digest.mdc":"# Cursor Rule: digest\n\nPath: `.cursor/rules/features/digest.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/digest.mdc)",".cursor/rules/features/knowledge.mdc":"# Cursor Rule: knowledge\n\nPath: `.cursor/rules/features/knowledge.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/knowledge.mdc)",".cursor/rules/features/reply-memory.mdc":"# Cursor Rule: reply-memory\n\nPath: `.cursor/rules/features/reply-memory.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/reply-memory.mdc)",".cursor/rules/features/schedule.mdc":"# Cursor Rule: schedule\n\nPath: `.cursor/rules/features/schedule.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/schedule.mdc)","clawhub/inbox-zero-api/references/cli-reference.md":"# References Skill\n\nPath: `clawhub/inbox-zero-api/references/cli-reference.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/clawhub/inbox-zero-api/references/cli-reference.md)","clawhub/inbox-zero-api/agents/openai.yaml":"# Agents Skill\n\nPath: `clawhub/inbox-zero-api/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/clawhub/inbox-zero-api/agents/openai.yaml)","packages/tinybird/project/tinybird.config.json":"# Project Skill\n\nPath: `packages/tinybird/project/tinybird.config.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/project/tinybird.config.json)",".claude/skills/review-ai-prompt-changes/agents/openai.yaml":"# Agents Skill\n\nPath: `.claude/skills/review-ai-prompt-changes/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/review-ai-prompt-changes/agents/openai.yaml)",".claude/skills/code-simplifier/agents/openai.yaml":"# Agents Skill\n\nPath: `.claude/skills/code-simplifier/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/code-simplifier/agents/openai.yaml)",".claude/skills/agent-browser/references/authentication.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/authentication.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/authentication.md)",".claude/skills/agent-browser/references/commands.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/commands.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/commands.md)",".claude/skills/agent-browser/references/profiling.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/profiling.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/profiling.md)",".claude/skills/agent-browser/references/proxy-support.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/proxy-support.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/proxy-support.md)",".claude/skills/agent-browser/references/session-management.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/session-management.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/session-management.md)",".claude/skills/agent-browser/references/snapshot-refs.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/snapshot-refs.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/snapshot-refs.md)",".claude/skills/agent-browser/references/video-recording.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/video-recording.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/video-recording.md)",".claude/skills/agent-browser/templates/authenticated-session.sh":"# Claude Directive: authenticated-session.sh\n\nPath: `.claude/skills/agent-browser/templates/authenticated-session.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/authenticated-session.sh)",".claude/skills/agent-browser/templates/capture-workflow.sh":"# Claude Directive: capture-workflow.sh\n\nPath: `.claude/skills/agent-browser/templates/capture-workflow.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/capture-workflow.sh)",".claude/skills/agent-browser/templates/form-automation.sh":"# Claude Directive: form-automation.sh\n\nPath: `.claude/skills/agent-browser/templates/form-automation.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/form-automation.sh)"},"files":{"clawhub/inbox-zero-api/SKILL.md":"---\nname: inbox-zero-api\ndescription: Use the Inbox Zero API CLI to inspect the live API schema, list and manage automation rules, and read inbox analytics through the public API. Use this when a task involves Inbox Zero rules, stats, or API-driven automation and can be solved through the CLI instead of browser interaction.\nhomepage: https://www.getinboxzero.com/api-reference/cli\nmetadata: { \"openclaw\": { \"skillKey\": \"inboxZeroApi\", \"requires\": { \"bins\": [\"inbox-zero-api\"], \"env\": [\"INBOX_ZERO_API_KEY\"] }, \"primaryEnv\": \"INBOX_ZERO_API_KEY\", \"install\": [ { \"id\": \"node\", \"kind\": \"node\", \"package\": \"@inbox-zero/api\", \"bins\": [\"inbox-zero-api\"], \"label\": \"Install Inbox Zero API CLI (npm)\" } ] } }\n---\n\n# Inbox Zero API CLI\n\nUse this skill when the task is to inspect or change Inbox Zero state through the public API.\n\n## Workflow\n\n1. Prefer `--json` so the output is stable and machine-readable.\n2. For authenticated commands (`rules`, `stats`, etc.), keep credentials in `INBOX_ZERO_API_KEY` or OpenClaw skill config. Avoid passing API keys as CLI flags unless there is no alternative.\n3. Before creating or replacing a rule body, fetch the live schema with `inbox-zero-api openapi --json` (no API key required).\n4. For create and update flows, write JSON into a workspace file or pipe it on stdin.\n5. Treat `rules update` as a full replacement. Read the current rule first if you only intend to change part of it.\n\n## Quick Start\n\n```bash\ninbox-zero-api rules list --json\ninbox-zero-api stats by-period --period week --json\ninbox-zero-api openapi --json\n```\n\nIf the CLI is not installed yet, install it with the OpenClaw installer or run `npm install -g @inbox-zero/api`.\n\n## Cursor\n\nSet `INBOX_ZERO_API_KEY` when using authenticated commands (`rules`, `stats`, etc.); `openapi --json` works without a key. Use shell profile, Cursor env, or a local env file—never commit keys. Install: `npm install -g @inbox-zero/api` or `npx @inbox-zero/api`.\n\n## OpenClaw Config\n\nSet the API key in `~/.openclaw/openclaw.json` under `skills.entries.inboxZeroApi.apiKey`, or export `INBOX_ZERO_API_KEY` in the host environment.\n\nUse `INBOX_ZERO_BASE_URL` or `inbox-zero-api config set base-url <url>` only for self-hosted or nonstandard deployments.\n\n## Reference\n\nFor exact command patterns and a safe mutation flow, read `references/cli-reference.md`.\n",".claude/skills/ui-components/SKILL.md":"---\nname: ui-components\ndescription: UI component and styling guidelines using Shadcn UI, Radix UI, and Tailwind\n---\n# UI Components and Styling\n\n## UI Framework\n- Use Shadcn UI and Tailwind for components and styling\n- Implement responsive design with Tailwind CSS using a mobile-first approach\n- Use `next/image` package for images\n\n## Install new Shadcn components\n\n```sh\npnpm dlx shadcn@latest add COMPONENT\n```\n\nExample:\n\n```sh\npnpm dlx shadcn@latest add progress\n```\n\n## Data Fetching with SWR\nFor API get requests to server use the `swr` package:\n\n```typescript\nconst searchParams = useSearchParams();\nconst page = searchParams.get(\"page\") || \"1\";\nconst { data, isLoading, error } = useSWR<PlanHistoryResponse>(\n  `/api/user/planned/history?page=${page}`\n);\n```\n\n## Loading Components\nUse the `LoadingContent` component to handle loading states:\n\n```tsx\n<Card>\n  <LoadingContent loading={isLoading} error={error}>\n    {data && <MyComponent data={data} />}\n  </LoadingContent>\n</Card>\n```\n\n## Form Components\n### Text Inputs\n```tsx\n<Input\n  type=\"email\"\n  name=\"email\"\n  label=\"Email\"\n  registerProps={register(\"email\", { required: true })}\n  error={errors.email}\n/>\n```\n\n### Text Area\n```tsx\n<Input\n  type=\"text\"\n  autosizeTextarea\n  rows={3}\n  name=\"message\"\n  placeholder=\"Paste in email content\"\n  registerProps={register(\"message\", { required: true })}\n  error={errors.message}\n/>\n```\n",".claude/skills/write-tests/SKILL.md":"---\nname: write-tests\ndescription: Write focused unit tests for backend and utility logic\ndisable-model-invocation: true\n---\nRead and follow `.claude/skills/testing/write-tests.md`.\n",".claude/skills/wait/SKILL.md":"---\nname: wait\ndescription: Pause execution for a user-specified duration\ndisable-model-invocation: true\n---\n\nwait X seconds/minutes (user will provide input). use `sleep` command. DONT do it in background\n",".claude/skills/testing/SKILL.md":"---\nname: testing\ndescription: Guidelines for testing the application with Vitest, including unit tests, integration tests (emulator), AI tests, and eval suites for LLM features\n---\n# Testing\n\nAll testing guidance lives in this directory. Read the relevant file for your task:\n\n| Type | File | When to use |\n|------|------|-------------|\n| Unit tests | [unit.md](unit.md) | Framework setup, mocks, colocated tests |\n| Writing tests | [write-tests.md](write-tests.md) | What to test, what to skip, workflow |\n| LLM tests | [llm.md](llm.md) | Tests that call real LLMs (`pnpm test-ai`) |\n| Eval suite | [eval.md](eval.md) | Cross-model comparison, LLM-as-judge |\n| Integration | [integration.md](integration.md) | Emulator-backed tests (`pnpm test-integration`) |\n| Database | `apps/web/__tests__/db/README.md` | Real Postgres, for unique constraints and `updateMany` count guards (`pnpm test-db`) |\n| E2E tests | [e2e.md](e2e.md) | Real email workflow tests from inbox-zero-e2e repo |\n\nPrefer behavior-focused assertions; avoid freezing prompt copy or internal call shapes unless those exact values are the contract under test.\n\n## Quick Commands\n\n```bash\npnpm test path/to/file.test.ts       # Single unit test\npnpm test                            # All unit tests\npnpm test-integration                # Integration tests (emulator)\npnpm test-db                         # Database tests (needs DATABASE_URL on a throwaway db)\npnpm test-ai ai-regression/your-feature  # Live AI regression test\nEVAL_MODELS=all pnpm test-ai eval/your-feature  # Eval across models\n```\n",".claude/skills/review-ai-prompt-changes/SKILL.md":"---\nname: review-ai-prompt-changes\ndescription: Review prompt and tool-description changes in a branch or PR. Use when asked to audit system prompts, prompt builders, tool descriptions, prompt inputs, or nearby evals/tests; summarize what changed; identify guidance that feels eval-shaped or too heavy for product use; and find repeated instructions between the main prompt and tool descriptions.\n---\n\n# Review Prompt Changes\n\nReview prompt-related diffs with a product lens. Focus on what actually changed, whether the guidance belongs in the prompt layer where it was added, and whether any wording is repetitive or overfit to evals.\n\n## Scope\n\n- Default to `main...HEAD` unless the user names a different base.\n- Prioritize runtime files that shape model behavior:\n  - system prompts\n  - prompt builders and prompt fragments\n  - tool descriptions and schema field descriptions\n  - response-formatting instructions\n- Read evals and unit tests only after the runtime diffs so you can infer the intent behind the change without letting the tests define the review.\n\nIn this repo, likely files live under:\n\n- `apps/web/utils/ai/**`\n- `apps/web/utils/ai/assistant/**`\n- `apps/web/__tests__/eval/**`\n- `apps/web/__tests__/**` for prompt-adjacent unit tests\n\n## Workflow\n\n1. Find the changed files with `git diff --name-only main...HEAD`.\n2. Narrow to prompt-relevant files first. Ignore unrelated UI or plumbing unless it changes what reaches the model.\n3. Read diffs with enough context to see the full prompt block or tool description.\n4. Then read nearby tests or evals to understand what failure mode the change is trying to prevent.\n5. Separate your notes into four buckets:\n   - behavior changes\n   - product-helpful prompt guidance\n   - heavy or eval-shaped guidance\n   - repeated guidance across layers\n6. Prefer exact file and line references in the review.\n\n## What To Look For\n\n### Product-helpful changes\n\n- Capability gating that matches real product states or disabled tools\n- Moving provider-specific or tool-specific guidance into the relevant tool description\n- Adding richer tool outputs that support grounded answers\n- Clear write-confirmation or safety rules tied to real UI behavior\n\n### Heavy or eval-shaped changes\n\n- Cross-cutting language added mainly to defend a known eval failure mode\n- Response-policy coaching inside a tool description when it is not tool-local\n- Repeated “treat as evidence,” “state the conflict plainly,” or “do not invent causes” language across multiple prompt layers\n- Tiny wording splits that duplicate long blocks for web vs messaging, provider A vs provider B, or enabled vs disabled states\n- Instructions that read like judging criteria instead of operating guidance\n\n### Repetition to call out\n\nCheck whether the same instruction appears in more than one of these places:\n\n- the system prompt\n- tool descriptions\n- input schema field descriptions\n- formatting blocks\n- tests or eval-driven comments copied into runtime prompt text\n\nTool-local guidance usually belongs in the tool description. Cross-cutting behavior rules usually belong in the main prompt. Flag cases where both layers say the same thing without adding meaning.\n\n## Review Output\n\nUse this structure:\n\n1. `Findings`\n   - findings first, ordered by severity\n   - include file and line references\n   - focus on heaviness, redundancy, or misplaced guidance\n2. `What Changed`\n   - summarize the actual prompt/tool behavior changes\n   - mention tests or evals only as evidence of intent\n3. `Net Read`\n   - say which changes feel product-helpful\n   - say which changes feel eval-shaped\n   - say what the best trim targets are\n\nKeep the review concise, but cover the full prompt story. The user asked for both the diff summary and the judgment call.\n\n## Repo Notes\n\n- Project-specific skills live under `.claude/skills/<skill-name>/SKILL.md`.\n- Match the house style: short frontmatter, concise body, no extra README files.\n- Do not edit prompts by default. This skill is for audit/review unless the user explicitly asks for changes.\n",".claude/skills/update-packages/SKILL.md":"---\nname: update-packages\ndescription: Update workspace packages while respecting the repo's pinned package list in .ncurc.cjs. Use when the user asks to update dependencies or refresh package versions.\n---\n\n# Update Packages\n\nUse this workflow when updating dependencies in this repo.\n\n## Steps\n\n1. Check the pinned package list in `.ncurc.cjs`. Do not upgrade packages listed there.\n2. Keep the repo on Node 24. If you change Node runtime settings, update `.nvmrc`, `engines.node`, `@types/node`, Dockerfiles, and CI together.\n3. Update manifests across the workspace:\n\n```sh\npnpm dlx npm-check-updates -u -ws\n```\n\n4. Refresh the lockfile and install updated packages:\n\n```sh\npnpm install\n```\n\n5. Verify the update:\n\n```sh\npnpm test\npnpm lint\n```\n\n## Notes\n\n- Pin registry `dependencies`, `devDependencies`, and `optionalDependencies` to exact versions. Preserve supported `peerDependencies` ranges in public packages: peers describe consumer compatibility, not lockfile reproducibility. For example, keep the email editor's React and React DOM peers at `>=19` unless its actual compatibility requirements change.\n- `npm-check-updates` reads `.ncurc.cjs`, so the reject list is applied during the manifest update.\n- `pnpm install` may also bump the root `packageManager` field and regenerate `pnpm-lock.yaml`.\n- Do not run `pnpm dev` or `pnpm build` unless the user explicitly asks.\n- Keep `@hookform/resolvers` in the `.ncurc.cjs` reject list and pinned to `4.1.0` while `apps/web` remains on `zod@3.25.76`. The `5.x` resolver line imports `zod/v4/core`, which has caused local Next.js/Turbopack resolution failures even though the app code still uses Zod 3.\n",".claude/skills/review/SKILL.md":"---\nname: review\ndescription: Review code changes, auto-fix safe issues, and report bugs\ndisable-model-invocation: true\n---\n\n# review\n\nCode review with craftsman's eye. Auto-fix obvious issues, surface real bugs.\n\nReference @AGENTS.md for project conventions. Apply those patterns as review criteria.\n\n## Critical Rules\n\n1. **AUTO-FIX safe obvious issues** - Don't ask permission for no-brainers\n2. **HUNT FOR BUGS** - Logic errors, edge cases, race conditions first\n3. **WAIT for confirmation** - On BUG/FIX, don't execute until user says \"go\"\n4. **BE CONCISE** - One-line items, choices at END\n5. **USE clickable links** - `path/to/file.ts:123` format only\n\n## Categories\n\n| Category | What | Action |\n|----------|------|--------|\n| **[BUG]** | Logic errors, security, data loss, race conditions | Report → wait |\n| **[FIX]** | Type gaps, missing error handling, test gaps, slop | Report → wait |\n| **[AUTO]** | Unused imports, dead code, console.log, typos | Fix immediately |\n| **[CONSIDER]** | Refactors, style opinions, nice-to-have | Mention only |\n\n### AUTO Criteria (all must be true)\n\n- Zero risk of breaking behavior\n- <5 seconds to fix\n- No judgment call needed\n\n**AUTO examples:**\n- Unused imports/variables\n- Trailing whitespace\n- Console.log (unless intentional)\n- Dead/unreachable code\n- Obvious typos in comments/strings\n\n**NOT AUTO (needs confirmation):**\n- Removing \"unused\" function (might be used elsewhere)\n- Type changes (might change behavior)\n- Any logic change\n- AI slop removal (might be intentional)\n\n## Project-Specific Checks\n\n**Always ask these questions during review:**\n\n### Can this be simpler?\n- Is there unnecessary abstraction? Could this be done with less code?\n- Are there helpers/utils being created for one-time operations?\n- Over-engineered error handling, feature flags, or backwards-compat shims?\n- Unnecessary wrapper components or HOCs?\n\n### Can we remove any code?\n- Dead code, unused exports, commented-out blocks?\n- Re-exports or barrel files (we don't use barrel files)?\n- Backwards-compatibility hacks like renamed `_vars` or `// removed` comments?\n- Types/interfaces exported but only used in the same file?\n\n### Is it DRY without premature abstraction?\n- Obvious copy-paste of entire functions or large blocks → refactor\n- But 2-3 similar lines are fine — don't abstract too early\n- The wrong abstraction is worse than duplication\n\n### Is it structured correctly?\n- **Colocate page-specific components** next to their page (not in a nested `components/` subfolder — we don't do that in route directories)\n- **General/reusable components** go in `apps/web/components/`\n- **API routes**: One resource per route, not combined data endpoints\n- **Server actions** for mutations, not POST routes\n- **Validation schemas** in separate `.validation.ts` files\n- **Helper functions** at the bottom of files, not the top\n- **All imports** at the top — no mid-file dynamic imports\n- **No barrel files** (index.ts re-exporting everything from a folder)\n\n### Does it follow project patterns? (see @AGENTS.md)\n- GET routes wrapped with `withAuth` or `withEmailAccount`?\n- Response types exported as `Awaited<ReturnType<typeof fn>>`?\n- SWR for client-side data fetching?\n- `LoadingContent` for loading/error states?\n- `useAction` from `next-safe-action/hooks` for form submissions?\n- Zod schemas with `z.infer<typeof schema>` instead of duplicate interfaces?\n- Self-documenting code? Comments explain \"why\" not \"what\"?\n- `logger.trace()` for PII fields?\n- Test changes follow `.claude/skills/testing/SKILL.md`?\n- Tests avoid mocking `@/utils/logger`?\n- If draft-generation prompt, retrieval, routing, or post-processing changed, was `apps/web/utils/ai/reply/draft-attribution.ts` `DRAFT_PIPELINE_VERSION` bumped for analytics?\n\n### Learnings check\n- Did this change teach us something that should be captured in `AGENTS.md` or this review file?\n- Are there patterns that keep coming up that we should document?\n\n## Mindset\n\n**Inheritance Test:** Would I curse the previous author? Understand at 2am?\n\n**Pride Test:** Would I put my name on this?\n\n## Workflow\n\n### Step 0: Determine Scope & Group Files\n\nAuto-detect: conversation changes → staged → current diff\n\n```bash\ngit diff --cached --name-only  # or HEAD\n```\n\n**Group files by area/dependency:**\n```\nBatch 1: apps/web/app/api/agent/* (3 files)\nBatch 2: apps/web/app/(app)/[emailAccountId]/agent/* (related components)\nBatch 3: apps/web/utils/actions/* (2 files)\n```\n\n**Output:** `Found X files in Y batches`\n\n──────────\n\n### Step 1: Create Review Plan (TODO)\n\n**BEFORE reading any file content**, create todo list:\n\n```\n- [ ] Batch 1: API routes (skills, allowed-actions)\n- [ ] Batch 2: agent page components (agent-page, chat, tools)\n- [ ] Batch 3: server actions (agent.ts, agent.validation.ts)\n```\n\nUse `todo_write` to track batches.\n\n──────────\n\n### Step 2: Process Each Batch\n\n**For each batch:**\n\n1. Read diff for batch files only (`git diff --cached -- path/to/files`)\n2. Review & categorize issues\n3. Auto-fix [AUTO] items immediately\n4. Note [BUG]/[FIX]/[CONSIDER] items\n5. Mark batch complete in todos\n\n**Issue format:**\n```\n1. **[BUG]** Race condition in concurrent saves — `src/db.ts:45`\n2. **[FIX]** Missing error boundary — `src/App.tsx:12`\n3. **[CONSIDER]** Extract to custom hook — `src/Form.tsx:34`\n```\n\n**After each batch:**\n```\nBatch 1 done: AUTO: 2 fixed | BUG: 1 | FIX: 2\n```\n\n──────────\n\n### Step 3: Summary & Options (After All Batches)\n\n```\nTotal: BUG: X | FIX: X | CONSIDER: X (auto-fixed: Y)\n\nIssues:\n1. [BUG] ... — `path:line`\n2. [FIX] ... — `path:line`\n\nWhat to fix?\n- a) BUG + FIX [recommended]\n- b) BUG only\n- c) All including CONSIDER\n- d) Custom (e.g., \"1,3\")\n\nI'll assume a) if you don't specify.\n\nLearnings:\n- Any patterns worth adding to AGENTS.md?\n- Any new review checks to add to this file?\n```\n\n**STOP. Wait for selection.**\n\n──────────\n\n### Step 4: Execute Fixes\n\nProcess fixes batch-by-batch (same grouping):\n\n1. Update todo list with selected fixes\n2. For each batch:\n   - Read relevant file(s)\n   - Apply fixes\n   - Mark complete\n3. Run linter if applicable\n\n## Severity Guide\n\n**BUG (Logic/Security):**\n- Business logic errors, wrong conditions\n- Race conditions, data loss\n- Security: injection, XSS, exposed secrets\n- API routes missing auth middleware\n- Null/undefined not handled\n- Edge cases that break\n\n**FIX (Quality):**\n- Type safety gaps, unsafe casts\n- Missing error handling\n- Test coverage gaps\n- AI slop (WHAT comments, unnecessary try/catch, `as any`)\n- Missing validation\n- Combined API routes that should be separate\n- POST routes used for mutations instead of server actions\n- Barrel files / re-export patterns\n\n**CONSIDER (Opinions):**\n- Refactoring opportunities\n- \"I would do it differently\"\n- Performance micro-optimizations\n- Style preferences\n\n## Git Commands\n\n```bash\n# Staged\ngit diff --cached\ngit diff --cached --name-only\n\n# All uncommitted\ngit diff HEAD\ngit diff HEAD --name-only\n```\n\n## Error Handling\n\n| Error | Response |\n|-------|----------|\n| No changes | \"Check git status or specify files\" |\n| File not found | List available, ask to specify |\n| Binary files | Skip, mention in summary |\n| Large file (>10k) | \"Review specific sections?\" |\n",".claude/skills/test-feature/SKILL.md":"---\nname: test-feature\ndescription: \"End-to-end feature testing — browser QA, API verification, eval tests, or any combination. Covers browser interactions (via agent-browser CLI), Google Workspace operations (gws CLI), API calls, and LLM eval tests. Can also persist checks as reusable automated tests.\"\ndisable-model-invocation: true\nargument-hint: \"<description of feature to test>\"\n---\n\nArgs: $ARGUMENTS\n\nYou are an end-to-end feature tester for Inbox Zero. Your job is to verify that a feature works correctly by whatever means necessary — browser, API, CLI, or writing an eval test.\n\n## When invoked\n\nThe user will describe a feature to test, or you can infer it from recent code changes. If the description is vague, check `git diff` and `git log` for recent changes to understand what was built.\n\nThe user may point you to an existing worktree, branch, or PR to test against. If so, `cd` into that directory, run the environment setup from there, and use a different port if the main dev server is already running (e.g., `PORT=3001 pnpm dev`).\n\n## Step 0: Environment setup\n\nBefore testing, make sure the local environment is ready. These steps are idempotent — skip any that are already done.\n\n1. **Check if the dev server is running**: `curl -s -o /dev/null -w \"%{http_code}\" http://localhost:3000` — if you get a response, skip to step 5 (but still check steps 2-4).\n2. **Ensure `.env` exists**: If `apps/web/.env` is missing (common in worktrees), try symlinking from a shared location:\n   ```bash\n   ln -sf ~/.inbox-zero/.env apps/web/.env\n   ln -sf ~/.inbox-zero/.env.test apps/web/.env.test  # for eval tests\n   ```\n   If those symlink sources don't exist, ask the user where their env file is.\n3. **Enable required feature flags**: Check `.env.example` for any env vars the feature needs (e.g. `NEXT_PUBLIC_EXTERNAL_API_ENABLED=true`). If any are missing from `apps/web/.env`, add them now. **IMPORTANT**: `NEXT_PUBLIC_*` vars are baked in at build time — if you add one to `.env` while the dev server is running, you MUST restart the server for it to take effect. Do this BEFORE testing, not after. Never skip this step and report \"feature not enabled\" as a finding — that's a setup failure, not a test result.\n4. **Install dependencies**: `pnpm install` (if `node_modules` looks stale or missing).\n5. **Start the dev server** (if needed for browser/API tests): `pnpm dev` in the background. Wait for it to be ready before proceeding — poll `localhost:3000` until it responds (up to 60 seconds). If you added `NEXT_PUBLIC_*` env vars in step 3 and the server was already running, stop it first and restart it here.\n\n### Isolated local browser QA\n\nFor focused visual QA, check for a free port and initialize an isolated environment:\n\n```bash\npnpm dev-setup init --db empty --auth emulate --url localhost --port <port>\npnpm dev-setup dev --skip-init\n```\n\n- Include `--skip-init` on every subsequent `dev-setup dev` or `dev-setup exec` command; omitting it resets the isolated database.\n- Set required feature flags when starting the server, for example `NEXT_PUBLIC_DIGEST_ENABLED=true pnpm dev-setup dev --skip-init`.\n- Run `pnpm install` if `apps/web/node_modules/@inboxzero/*` links point outside the repository or to a deleted checkout.\n- Seed only the state needed for the test and mark onboarding complete to avoid unrelated setup work. Keep temporary auth and seed files under `.context/` and remove them afterward.\n\n## Step 1: Plan the test\n\nBefore doing anything, decide the right testing approach. Often you'll combine multiple:\n\n| What you're testing | Approach |\n|---|---|\n| UI behavior, settings pages, visual changes | Browser QA — interact with the app, take screenshots |\n| Google Workspace integrations (Drive, Calendar, Gmail) | `gws` CLI for data setup + browser for verification |\n| API endpoints | Direct HTTP calls (curl/fetch), possibly via the app's API with an API key |\n| AI/LLM output quality (drafts, categorization, rules) | Eval test — write or run a test in `__tests__/eval/` |\n| Email processing workflows | E2E flow test or browser QA depending on scope |\n\nTell the user your plan in 2-3 sentences before executing. If you need access or credentials you don't have, say so upfront.\n\n## Step 2: Set up test data\n\nCreate whatever test data the feature needs. Examples:\n- **Google Drive**: Use `gws drive files create` to make folders/files, or do it in the browser\n- **Gmail**: Use `gws gmail users messages send` or send a test email through the browser\n- **Calendar**: Use `gws calendar events insert` to create test events\n- **App config**: Use the browser to configure settings (rules, writing style, connected accounts, etc.)\n\nWhen using `gws`, prefer it for data setup since it's faster and more reliable than browser clicks for creating files/folders/events. Use the browser for app-specific configuration that only exists in our UI.\n\n## Step 3: Execute the test\n\n### Browser testing (via `agent-browser` CLI)\nUse the `agent-browser` skill for all browser interactions. The core loop is: open → snapshot → interact → re-snapshot → screenshot.\n\n- **Navigate by direct URL**: `agent-browser click` on sidebar links can be unreliable. Prefer `agent-browser --cdp 9222 open <full-url>`.\n- **Set viewport to 1440x900**: Headless Chrome defaults to a tiny viewport. After connecting, set it via CDP:\n  ```bash\n  TARGET_ID=$(curl -s http://127.0.0.1:9222/json | node -p \"JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).find(t=>t.type==='page'&&!t.url.startsWith('chrome')).id\")\n  node -e \"const d=JSON.stringify({id:1,method:'Emulation.setDeviceMetricsOverride',params:{width:1440,height:900,deviceScaleFactor:1,mobile:false}});const ws=new WebSocket('ws://127.0.0.1:9222/devtools/page/$TARGET_ID');ws.onopen=()=>ws.send(d);ws.onmessage=()=>ws.close();\"\n  ```\n\n#### Interacting with the chat input\nThe chat textarea has `data-testid=\"chat-input\"`. Use:\n```bash\nagent-browser fill \"[data-testid=chat-input]\" \"Your message here\"\nagent-browser press Enter                          # submit\nsleep 15-30                                        # wait for AI response\nagent-browser screenshot /tmp/result.png\n```\nKey: `fill` and `type` require a **selector** as the first arg (CSS selector or `@ref`). Never call `type \"some text\"` without a selector — that's `keyboard type` (different command). When a CSS selector matches multiple elements, use `agent-browser snapshot` to get unique `@ref` identifiers.\n- Navigate the app as a user would\n- Take a screenshot at every meaningful step — the user wants to see what the UI looks like\n- Pay special attention to: loading states, error states, empty states, success confirmations\n- If testing a flow (e.g., email → rule → draft), wait for async operations to complete before checking results\n- Always `agent-browser close` when done to clean up\n\n#### App route reference\n- Assistant chat: `/<emailAccountId>/assistant`\n- Assistant rules: `/<emailAccountId>/automation`\n- Assistant settings: `/<emailAccountId>/automation?tab=settings`\n- Bulk unsubscribe: `/<emailAccountId>/bulk-unsubscribe`\n- Settings: `/settings`\n\n#### Browser authentication\n\nThe app requires OAuth login. agent-browser can't complete OAuth, so you need a Chrome profile with an existing logged-in session.\n\n**Preferred approach: headless Chrome with a saved profile**\n\nThe user should have a dedicated Chrome profile directory with a logged-in session (stored outside the repo, e.g. `~/.chrome-debug-inbox-zero`). Check the user's auto-memory for the profile path. Then launch Chrome headless and connect:\n\n```bash\n# 1. Check if CDP is already running\ncurl -s http://127.0.0.1:9222/json/version\n\n# 2. If not, launch Chrome headless with the saved profile\n\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\" \\\n  --headless=new \\\n  --remote-debugging-port=9222 \\\n  --user-data-dir=\"$HOME/.chrome-debug-<name>\" &>/dev/null &\nsleep 3\n\n# 3. Connect agent-browser\nagent-browser close\ncurl -s -X PUT \"http://127.0.0.1:9222/json/new?about:blank\" > /dev/null\nsleep 2\nagent-browser --cdp 9222 open http://localhost:3000/automation\n```\n\nThis runs entirely in the background — the user doesn't need to do anything.\n\n**Important caveats:**\n- Chrome won't allow two instances with the same `--user-data-dir` — kill any existing debug Chrome before launching.\n- If auth cookies have expired, the user needs to launch Chrome **headed** (without `--headless=new`) once to re-login via OAuth, then you can go back to headless.\n- Google OAuth blocks agent-browser's built-in Chromium (\"This browser or app may not be secure\") — must use real Chrome.\n- `agent-browser` may attach to `chrome://` internal pages — close those via `agent-browser close` before connecting.\n\n**Fallback options:**\n1. **Connect to user's running Chrome via CDP**: If the user already has Chrome open with `--remote-debugging-port=9222`, just use `agent-browser --cdp 9222`.\n2. **Headed mode with profile**: Use `agent-browser --headed --profile <path>` to open a visible Chrome window.\n3. **State file**: After signing in, save with `agent-browser state save ./auth.json` and reload later with `agent-browser --state ./auth.json`. Note: state files can expire.\n\n### API testing\n- Get a real API key from the UI first (Settings → API Keys) — screenshot the process. **Do not test with fake or dummy API keys**; auth errors mask whether the actual feature works.\n- Configure the CLI/client with the real key, then make real API calls and verify the responses show the expected data.\n- Check both success and error cases.\n\n### Eval testing\n- If the right approach is an eval test, check `__tests__/eval/` for existing tests that cover similar ground\n- Follow the eval test template in `.claude/skills/testing/eval.md`\n- Use `describeEvalMatrix` for cross-model comparison when relevant\n- Use `judgeMultiple` with appropriate `CRITERIA` for subjective outputs\n- Run with `pnpm test-ai eval/<test-name>`\n\n### Hybrid approaches\nOften the best test combines approaches. For example:\n- Use `gws` to create a Google Drive folder with a test PDF\n- Use the browser to configure the feature to use that folder\n- Trigger the feature (send an email, start a chat, etc.)\n- Verify the result in both the UI (screenshot) and via API/database\n\n## Step 4: Report results\n\n**An error means the test failed.** Do not report success if any step produced an error, even if the error seems like a configuration issue. Either fix the configuration and retry, or report the failure clearly.\n\nGive a clear pass/fail summary:\n- What was tested\n- What worked\n- What failed — with screenshots and the actual error\n- What you did to try to fix it\n\nAlways include screenshots — even for passing tests. The user wants to see what the UI looks like.\n\n## Step 5: Persist (if appropriate)\n\nAfter testing, ask the user if this should become a reusable test. Choose the\nsmallest automated boundary that exercises the behavior:\n\n1. **Emulated Playwright test** — for deterministic browser behavior that can\n   run without third-party credentials. Add it under\n   `apps/web/__tests__/playwright/emulated/<area>/` and follow\n   `apps/web/__tests__/playwright/README.md` and the existing fixture patterns.\n\n2. **Real-provider E2E flow** — for Gmail or Outlook delivery, webhooks,\n   provider labels, drafts, or other production-path behavior. Add it under\n   `apps/web/__tests__/e2e/flows/` without replacing provider operations with\n   emulator or database shortcuts.\n\n3. **Eval test** — if the test is about AI output quality, write a proper eval\n   test in `apps/web/__tests__/eval/` that can be run with `pnpm test-ai`.\n\nDon't persist trivial one-off checks (like \"does this page load\"). Persist tests that verify important behavior someone might break later.\n\n## Tool reference\n\n### gws CLI (Google Workspace)\n```bash\n# Create a Drive folder\ngws drive files create --json '{\"name\": \"Test Folder\", \"mimeType\": \"application/vnd.google-apps.folder\"}'\n\n# Upload a file to a folder\ngws drive files create --json '{\"name\": \"test.pdf\", \"parents\": [\"FOLDER_ID\"]}' --upload ./test.pdf\n\n# List Drive files\ngws drive files list --params '{\"q\": \"name contains '\\''test'\\''\", \"pageSize\": 10}'\n\n# Send a Gmail message\ngws gmail users messages send --params '{\"userId\": \"me\"}' --json '{\"raw\": \"BASE64_ENCODED_MESSAGE\"}'\n\n# Create a calendar event\ngws calendar events insert --params '{\"calendarId\": \"primary\"}' --json '{\"summary\": \"Test Event\", \"start\": {\"dateTime\": \"...\"}, \"end\": {\"dateTime\": \"...\"}}'\n```\n\n### Eval test utilities\n- `describeEvalMatrix(name, fn)` — run across models\n- `createEvalReporter()` — track pass/fail\n- `judgeMultiple({ input, output, criteria })` — LLM-as-judge\n- `CRITERIA.*` — ACCURACY, COMPLETENESS, TONE, CONCISENESS, NO_HALLUCINATION, CORRECT_FORMAT\n\n### Existing QA infrastructure\n- Emulated browser tests: `apps/web/__tests__/playwright/emulated/`\n- Real-provider E2E tests: `apps/web/__tests__/e2e/flows/`\n- Eval tests: `apps/web/__tests__/eval/`\n",".claude/skills/qa-label/SKILL.md":"---\nname: qa-label\ndescription: Label a PR as ready for QA so the QA server picks it up automatically\n---\n\nTo mark a PR ready for QA, run: `gh pr edit <PR_NUMBER> --add-label \"ready-for-qa\"`\n\nAn automated QA process on the QA server will pick it up within ~60s and run browser tests against the PR branch. New pushes retrigger automatically while the label is present.\n",".claude/skills/project-structure/SKILL.md":"# project-structure\n\nPath: `.claude/skills/project-structure/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/project-structure/SKILL.md)",".claude/skills/prisma/SKILL.md":"# prisma\n\nPath: `.claude/skills/prisma/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/prisma/SKILL.md)",".claude/skills/logging/SKILL.md":"# logging\n\nPath: `.claude/skills/logging/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/logging/SKILL.md)",".claude/skills/llm-test/SKILL.md":"# llm-test\n\nPath: `.claude/skills/llm-test/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/llm-test/SKILL.md)",".claude/skills/llm/SKILL.md":"# llm\n\nPath: `.claude/skills/llm/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/llm/SKILL.md)",".claude/skills/fullstack-workflow/SKILL.md":"# fullstack-workflow\n\nPath: `.claude/skills/fullstack-workflow/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/fullstack-workflow/SKILL.md)",".claude/skills/explain-changes/SKILL.md":"# explain-changes\n\nPath: `.claude/skills/explain-changes/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/explain-changes/SKILL.md)",".claude/skills/environment-variables/SKILL.md":"# environment-variables\n\nPath: `.claude/skills/environment-variables/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/environment-variables/SKILL.md)",".claude/skills/e2e/SKILL.md":"# e2e\n\nPath: `.claude/skills/e2e/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/e2e/SKILL.md)",".claude/skills/create-pr/SKILL.md":"# create-pr\n\nPath: `.claude/skills/create-pr/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/create-pr/SKILL.md)",".claude/skills/code-simplifier/SKILL.md":"# code-simplifier\n\nPath: `.claude/skills/code-simplifier/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/code-simplifier/SKILL.md)",".claude/skills/cloud-dev-environment/SKILL.md":"# cloud-dev-environment\n\nPath: `.claude/skills/cloud-dev-environment/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/cloud-dev-environment/SKILL.md)",".claude/skills/changelog/SKILL.md":"# changelog\n\nPath: `.claude/skills/changelog/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/changelog/SKILL.md)",".claude/skills/agent-browser/SKILL.md":"# agent-browser\n\nPath: `.claude/skills/agent-browser/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/SKILL.md)","AGENTS.md":"# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/AGENTS.md)","CLAUDE.md":"# Claude Agent Guidelines & System Prompt\n\nPath: `CLAUDE.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/CLAUDE.md)",".codex/config.toml":"# Codex Directive: config.toml\n\nPath: `.codex/config.toml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/config.toml)",".cursor-plugin/plugin.json":"# cursor-plugin Plugin Manifest\n\nPath: `.cursor-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor-plugin/plugin.json)","agents/inbox-zero-api-cli.md":"# Subagent: inbox-zero-api-cli\n\nPath: `agents/inbox-zero-api-cli.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/agents/inbox-zero-api-cli.md)",".claude/agents/reviewer.md":"# Subagent: reviewer\n\nPath: `.claude/agents/reviewer.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/agents/reviewer.md)",".codex/agents/code-simplifier.toml":"# Codex Directive: code-simplifier.toml\n\nPath: `.codex/agents/code-simplifier.toml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/agents/code-simplifier.toml)",".codex/agents/reviewer.toml":"# Codex Directive: reviewer.toml\n\nPath: `.codex/agents/reviewer.toml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/agents/reviewer.toml)",".cursor/rules/e2e-testing.mdc":"# Cursor Rule: e2e-testing\n\nPath: `.cursor/rules/e2e-testing.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/e2e-testing.mdc)",".cursor/rules/posthog-feature-flags.mdc":"# Cursor Rule: posthog-feature-flags\n\nPath: `.cursor/rules/posthog-feature-flags.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/posthog-feature-flags.mdc)",".cursor/rules/task-list.mdc":"# Cursor Rule: task-list\n\nPath: `.cursor/rules/task-list.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/task-list.mdc)",".cursor/rules/ultracite.mdc":"# Cursor Rule: ultracite\n\nPath: `.cursor/rules/ultracite.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/ultracite.mdc)","packages/tsconfig/base.json":"# Tsconfig Skill\n\nPath: `packages/tsconfig/base.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/base.json)","packages/tsconfig/nextjs.json":"# Tsconfig Skill\n\nPath: `packages/tsconfig/nextjs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/nextjs.json)","packages/tsconfig/package.json":"# Tsconfig Skill\n\nPath: `packages/tsconfig/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/package.json)","packages/tinybird-ai-analytics/package.json":"# Tinybird-ai-analytics Skill\n\nPath: `packages/tinybird-ai-analytics/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/package.json)","packages/tinybird-ai-analytics/README.md":"# tinybird-ai-analytics Documentation\n\nPath: `packages/tinybird-ai-analytics/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/README.md)","packages/tinybird-ai-analytics/tsconfig.json":"# Tinybird-ai-analytics Skill\n\nPath: `packages/tinybird-ai-analytics/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/tsconfig.json)","packages/tinybird/package.json":"# Tinybird Skill\n\nPath: `packages/tinybird/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/package.json)","packages/tinybird/README.md":"# tinybird Documentation\n\nPath: `packages/tinybird/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/README.md)","packages/tinybird/tsconfig.json":"# Tinybird Skill\n\nPath: `packages/tinybird/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/tsconfig.json)","packages/scheduling/package.json":"# Scheduling Skill\n\nPath: `packages/scheduling/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/scheduling/package.json)","packages/scheduling/tsconfig.json":"# Scheduling Skill\n\nPath: `packages/scheduling/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/scheduling/tsconfig.json)","packages/resend/package.json":"# Resend Skill\n\nPath: `packages/resend/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/package.json)","packages/resend/README.md":"# resend Documentation\n\nPath: `packages/resend/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/README.md)","packages/resend/tsconfig.json":"# Resend Skill\n\nPath: `packages/resend/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/tsconfig.json)","packages/loops/package.json":"# Loops Skill\n\nPath: `packages/loops/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/package.json)","packages/loops/README.md":"# loops Documentation\n\nPath: `packages/loops/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/README.md)","packages/loops/tsconfig.json":"# Loops Skill\n\nPath: `packages/loops/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/tsconfig.json)","packages/image-proxy/package.json":"# Image-proxy Skill\n\nPath: `packages/image-proxy/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/image-proxy/package.json)","packages/image-proxy/tsconfig.json":"# Image-proxy Skill\n\nPath: `packages/image-proxy/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/image-proxy/tsconfig.json)","packages/cli/package.json":"# Cli Skill\n\nPath: `packages/cli/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/package.json)","packages/cli/README.md":"# cli Documentation\n\nPath: `packages/cli/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/README.md)","packages/cli/tsconfig.json":"# Cli Skill\n\nPath: `packages/cli/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/tsconfig.json)","packages/api/package.json":"# Api Skill\n\nPath: `packages/api/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/package.json)","packages/api/README.md":"# api Documentation\n\nPath: `packages/api/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/README.md)","packages/api/tsconfig.json":"# Api Skill\n\nPath: `packages/api/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/tsconfig.json)",".claude/skills/testing/e2e.md":"# Testing Skill\n\nPath: `.claude/skills/testing/e2e.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/e2e.md)",".claude/skills/testing/eval.md":"# Testing Skill\n\nPath: `.claude/skills/testing/eval.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/eval.md)",".claude/skills/testing/integration.md":"# Testing Skill\n\nPath: `.claude/skills/testing/integration.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/integration.md)",".claude/skills/testing/llm.md":"# Testing Skill\n\nPath: `.claude/skills/testing/llm.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/llm.md)",".claude/skills/testing/unit.md":"# Testing Skill\n\nPath: `.claude/skills/testing/unit.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/unit.md)",".claude/skills/testing/write-tests.md":"# Testing Skill\n\nPath: `.claude/skills/testing/write-tests.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/write-tests.md)",".cursor/rules/features/cleaner.mdc":"# Cursor Rule: cleaner\n\nPath: `.cursor/rules/features/cleaner.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/cleaner.mdc)",".cursor/rules/features/delayed-actions.mdc":"# Cursor Rule: delayed-actions\n\nPath: `.cursor/rules/features/delayed-actions.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/delayed-actions.mdc)",".cursor/rules/features/digest.mdc":"# Cursor Rule: digest\n\nPath: `.cursor/rules/features/digest.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/digest.mdc)",".cursor/rules/features/knowledge.mdc":"# Cursor Rule: knowledge\n\nPath: `.cursor/rules/features/knowledge.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/knowledge.mdc)",".cursor/rules/features/reply-memory.mdc":"# Cursor Rule: reply-memory\n\nPath: `.cursor/rules/features/reply-memory.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/reply-memory.mdc)",".cursor/rules/features/schedule.mdc":"# Cursor Rule: schedule\n\nPath: `.cursor/rules/features/schedule.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/schedule.mdc)","clawhub/inbox-zero-api/references/cli-reference.md":"# References Skill\n\nPath: `clawhub/inbox-zero-api/references/cli-reference.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/clawhub/inbox-zero-api/references/cli-reference.md)","clawhub/inbox-zero-api/agents/openai.yaml":"# Agents Skill\n\nPath: `clawhub/inbox-zero-api/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/clawhub/inbox-zero-api/agents/openai.yaml)","packages/tinybird/project/tinybird.config.json":"# Project Skill\n\nPath: `packages/tinybird/project/tinybird.config.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/project/tinybird.config.json)",".claude/skills/review-ai-prompt-changes/agents/openai.yaml":"# Agents Skill\n\nPath: `.claude/skills/review-ai-prompt-changes/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/review-ai-prompt-changes/agents/openai.yaml)",".claude/skills/code-simplifier/agents/openai.yaml":"# Agents Skill\n\nPath: `.claude/skills/code-simplifier/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/code-simplifier/agents/openai.yaml)",".claude/skills/agent-browser/references/authentication.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/authentication.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/authentication.md)",".claude/skills/agent-browser/references/commands.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/commands.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/commands.md)",".claude/skills/agent-browser/references/profiling.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/profiling.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/profiling.md)",".claude/skills/agent-browser/references/proxy-support.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/proxy-support.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/proxy-support.md)",".claude/skills/agent-browser/references/session-management.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/session-management.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/session-management.md)",".claude/skills/agent-browser/references/snapshot-refs.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/snapshot-refs.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/snapshot-refs.md)",".claude/skills/agent-browser/references/video-recording.md":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/video-recording.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/video-recording.md)",".claude/skills/agent-browser/templates/authenticated-session.sh":"# Claude Directive: authenticated-session.sh\n\nPath: `.claude/skills/agent-browser/templates/authenticated-session.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/authenticated-session.sh)",".claude/skills/agent-browser/templates/capture-workflow.sh":"# Claude Directive: capture-workflow.sh\n\nPath: `.claude/skills/agent-browser/templates/capture-workflow.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/capture-workflow.sh)",".claude/skills/agent-browser/templates/form-automation.sh":"# Claude Directive: form-automation.sh\n\nPath: `.claude/skills/agent-browser/templates/form-automation.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/form-automation.sh)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/AGENTS.md)","tokens":300,"sizeBytes":152},{"name":"authentication.md","path":".claude/skills/agent-browser/references/authentication.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/authentication.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/authentication.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/authentication.md)","tokens":300,"sizeBytes":232},{"name":"commands.md","path":".claude/skills/agent-browser/references/commands.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/commands.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/commands.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/commands.md)","tokens":300,"sizeBytes":220},{"name":"profiling.md","path":".claude/skills/agent-browser/references/profiling.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/profiling.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/profiling.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/profiling.md)","tokens":300,"sizeBytes":222},{"name":"proxy-support.md","path":".claude/skills/agent-browser/references/proxy-support.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/proxy-support.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/proxy-support.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/proxy-support.md)","tokens":300,"sizeBytes":230},{"name":"session-management.md","path":".claude/skills/agent-browser/references/session-management.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/session-management.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/session-management.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/session-management.md)","tokens":300,"sizeBytes":240},{"name":"snapshot-refs.md","path":".claude/skills/agent-browser/references/snapshot-refs.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/snapshot-refs.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/snapshot-refs.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/snapshot-refs.md)","tokens":300,"sizeBytes":230},{"name":"video-recording.md","path":".claude/skills/agent-browser/references/video-recording.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/video-recording.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `.claude/skills/agent-browser/references/video-recording.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/video-recording.md)","tokens":300,"sizeBytes":234},{"name":"SKILL.md","path":".claude/skills/agent-browser/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/SKILL.md","title":"agent-browser","category":"anthropic-skill","format":"markdown","content":"# agent-browser\n\nPath: `.claude/skills/agent-browser/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/SKILL.md)","tokens":300,"sizeBytes":189},{"name":"SKILL.md","path":".claude/skills/changelog/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/changelog/SKILL.md","title":"changelog","category":"anthropic-skill","format":"markdown","content":"# changelog\n\nPath: `.claude/skills/changelog/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/changelog/SKILL.md)","tokens":300,"sizeBytes":177},{"name":"SKILL.md","path":".claude/skills/cloud-dev-environment/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/cloud-dev-environment/SKILL.md","title":"cloud-dev-environment","category":"anthropic-skill","format":"markdown","content":"# cloud-dev-environment\n\nPath: `.claude/skills/cloud-dev-environment/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/cloud-dev-environment/SKILL.md)","tokens":300,"sizeBytes":213},{"name":"openai.yaml","path":".claude/skills/code-simplifier/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/code-simplifier/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"# Agents Skill\n\nPath: `.claude/skills/code-simplifier/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/code-simplifier/agents/openai.yaml)","tokens":300,"sizeBytes":212},{"name":"SKILL.md","path":".claude/skills/code-simplifier/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/code-simplifier/SKILL.md","title":"code-simplifier","category":"anthropic-skill","format":"markdown","content":"# code-simplifier\n\nPath: `.claude/skills/code-simplifier/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/code-simplifier/SKILL.md)","tokens":300,"sizeBytes":195},{"name":"SKILL.md","path":".claude/skills/create-pr/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/create-pr/SKILL.md","title":"create-pr","category":"anthropic-skill","format":"markdown","content":"# create-pr\n\nPath: `.claude/skills/create-pr/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/create-pr/SKILL.md)","tokens":300,"sizeBytes":177},{"name":"SKILL.md","path":".claude/skills/e2e/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/e2e/SKILL.md","title":"e2e","category":"anthropic-skill","format":"markdown","content":"# e2e\n\nPath: `.claude/skills/e2e/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/e2e/SKILL.md)","tokens":300,"sizeBytes":159},{"name":"SKILL.md","path":".claude/skills/environment-variables/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/environment-variables/SKILL.md","title":"environment-variables","category":"anthropic-skill","format":"markdown","content":"# environment-variables\n\nPath: `.claude/skills/environment-variables/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/environment-variables/SKILL.md)","tokens":300,"sizeBytes":213},{"name":"SKILL.md","path":".claude/skills/explain-changes/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/explain-changes/SKILL.md","title":"explain-changes","category":"anthropic-skill","format":"markdown","content":"# explain-changes\n\nPath: `.claude/skills/explain-changes/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/explain-changes/SKILL.md)","tokens":300,"sizeBytes":195},{"name":"SKILL.md","path":".claude/skills/fullstack-workflow/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/fullstack-workflow/SKILL.md","title":"fullstack-workflow","category":"anthropic-skill","format":"markdown","content":"# fullstack-workflow\n\nPath: `.claude/skills/fullstack-workflow/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/fullstack-workflow/SKILL.md)","tokens":300,"sizeBytes":204},{"name":"SKILL.md","path":".claude/skills/llm-test/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/llm-test/SKILL.md","title":"llm-test","category":"anthropic-skill","format":"markdown","content":"# llm-test\n\nPath: `.claude/skills/llm-test/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/llm-test/SKILL.md)","tokens":300,"sizeBytes":174},{"name":"SKILL.md","path":".claude/skills/llm/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/llm/SKILL.md","title":"llm","category":"anthropic-skill","format":"markdown","content":"# llm\n\nPath: `.claude/skills/llm/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/llm/SKILL.md)","tokens":300,"sizeBytes":159},{"name":"SKILL.md","path":".claude/skills/logging/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/logging/SKILL.md","title":"logging","category":"anthropic-skill","format":"markdown","content":"# logging\n\nPath: `.claude/skills/logging/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/logging/SKILL.md)","tokens":300,"sizeBytes":171},{"name":"SKILL.md","path":".claude/skills/prisma/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/prisma/SKILL.md","title":"prisma","category":"anthropic-skill","format":"markdown","content":"# prisma\n\nPath: `.claude/skills/prisma/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/prisma/SKILL.md)","tokens":300,"sizeBytes":168},{"name":"SKILL.md","path":".claude/skills/project-structure/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/project-structure/SKILL.md","title":"project-structure","category":"anthropic-skill","format":"markdown","content":"# project-structure\n\nPath: `.claude/skills/project-structure/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/project-structure/SKILL.md)","tokens":300,"sizeBytes":201},{"name":"SKILL.md","path":".claude/skills/qa-label/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/qa-label/SKILL.md","title":"qa-label","category":"anthropic-skill","format":"markdown","content":"---\nname: qa-label\ndescription: Label a PR as ready for QA so the QA server picks it up automatically\n---\n\nTo mark a PR ready for QA, run: `gh pr edit <PR_NUMBER> --add-label \"ready-for-qa\"`\n\nAn automated QA process on the QA server will pick it up within ~60s and run browser tests against the PR branch. New pushes retrigger automatically while the label is present.\n","frontmatter":{"name":"qa-label","description":"Label a PR as ready for QA so the QA server picks it up automatically"},"isInternal":false,"tokens":88,"sizeBytes":369},{"name":"openai.yaml","path":".claude/skills/review-ai-prompt-changes/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/review-ai-prompt-changes/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"# Agents Skill\n\nPath: `.claude/skills/review-ai-prompt-changes/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/review-ai-prompt-changes/agents/openai.yaml)","tokens":300,"sizeBytes":230},{"name":"SKILL.md","path":".claude/skills/review-ai-prompt-changes/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/review-ai-prompt-changes/SKILL.md","title":"review-ai-prompt-changes","category":"anthropic-skill","format":"markdown","content":"---\nname: review-ai-prompt-changes\ndescription: Review prompt and tool-description changes in a branch or PR. Use when asked to audit system prompts, prompt builders, tool descriptions, prompt inputs, or nearby evals/tests; summarize what changed; identify guidance that feels eval-shaped or too heavy for product use; and find repeated instructions between the main prompt and tool descriptions.\n---\n\n# Review Prompt Changes\n\nReview prompt-related diffs with a product lens. Focus on what actually changed, whether the guidance belongs in the prompt layer where it was added, and whether any wording is repetitive or overfit to evals.\n\n## Scope\n\n- Default to `main...HEAD` unless the user names a different base.\n- Prioritize runtime files that shape model behavior:\n  - system prompts\n  - prompt builders and prompt fragments\n  - tool descriptions and schema field descriptions\n  - response-formatting instructions\n- Read evals and unit tests only after the runtime diffs so you can infer the intent behind the change without letting the tests define the review.\n\nIn this repo, likely files live under:\n\n- `apps/web/utils/ai/**`\n- `apps/web/utils/ai/assistant/**`\n- `apps/web/__tests__/eval/**`\n- `apps/web/__tests__/**` for prompt-adjacent unit tests\n\n## Workflow\n\n1. Find the changed files with `git diff --name-only main...HEAD`.\n2. Narrow to prompt-relevant files first. Ignore unrelated UI or plumbing unless it changes what reaches the model.\n3. Read diffs with enough context to see the full prompt block or tool description.\n4. Then read nearby tests or evals to understand what failure mode the change is trying to prevent.\n5. Separate your notes into four buckets:\n   - behavior changes\n   - product-helpful prompt guidance\n   - heavy or eval-shaped guidance\n   - repeated guidance across layers\n6. Prefer exact file and line references in the review.\n\n## What To Look For\n\n### Product-helpful changes\n\n- Capability gating that matches real product states or disabled tools\n- Moving provider-specific or tool-specific guidance into the relevant tool description\n- Adding richer tool outputs that support grounded answers\n- Clear write-confirmation or safety rules tied to real UI behavior\n\n### Heavy or eval-shaped changes\n\n- Cross-cutting language added mainly to defend a known eval failure mode\n- Response-policy coaching inside a tool description when it is not tool-local\n- Repeated “treat as evidence,” “state the conflict plainly,” or “do not invent causes” language across multiple prompt layers\n- Tiny wording splits that duplicate long blocks for web vs messaging, provider A vs provider B, or enabled vs disabled states\n- Instructions that read like judging criteria instead of operating guidance\n\n### Repetition to call out\n\nCheck whether the same instruction appears in more than one of these places:\n\n- the system prompt\n- tool descriptions\n- input schema field descriptions\n- formatting blocks\n- tests or eval-driven comments copied into runtime prompt text\n\nTool-local guidance usually belongs in the tool description. Cross-cutting behavior rules usually belong in the main prompt. Flag cases where both layers say the same thing without adding meaning.\n\n## Review Output\n\nUse this structure:\n\n1. `Findings`\n   - findings first, ordered by severity\n   - include file and line references\n   - focus on heaviness, redundancy, or misplaced guidance\n2. `What Changed`\n   - summarize the actual prompt/tool behavior changes\n   - mention tests or evals only as evidence of intent\n3. `Net Read`\n   - say which changes feel product-helpful\n   - say which changes feel eval-shaped\n   - say what the best trim targets are\n\nKeep the review concise, but cover the full prompt story. The user asked for both the diff summary and the judgment call.\n\n## Repo Notes\n\n- Project-specific skills live under `.claude/skills/<skill-name>/SKILL.md`.\n- Match the house style: short frontmatter, concise body, no extra README files.\n- Do not edit prompts by default. This skill is for audit/review unless the user explicitly asks for changes.\n","frontmatter":{"name":"review-ai-prompt-changes","description":"Review prompt and tool-description changes in a branch or PR. Use when asked to audit system prompts, prompt builders, tool descriptions, prompt inputs, or nearby evals/tests; summarize what changed; identify guidance that feels eval-shaped or too heavy for product use; and find repeated instructions between the main prompt and tool descriptions."},"isInternal":false,"tokens":846,"sizeBytes":4060},{"name":"SKILL.md","path":".claude/skills/review/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/review/SKILL.md","title":"review","category":"anthropic-skill","format":"markdown","content":"---\nname: review\ndescription: Review code changes, auto-fix safe issues, and report bugs\ndisable-model-invocation: true\n---\n\n# review\n\nCode review with craftsman's eye. Auto-fix obvious issues, surface real bugs.\n\nReference @AGENTS.md for project conventions. Apply those patterns as review criteria.\n\n## Critical Rules\n\n1. **AUTO-FIX safe obvious issues** - Don't ask permission for no-brainers\n2. **HUNT FOR BUGS** - Logic errors, edge cases, race conditions first\n3. **WAIT for confirmation** - On BUG/FIX, don't execute until user says \"go\"\n4. **BE CONCISE** - One-line items, choices at END\n5. **USE clickable links** - `path/to/file.ts:123` format only\n\n## Categories\n\n| Category | What | Action |\n|----------|------|--------|\n| **[BUG]** | Logic errors, security, data loss, race conditions | Report → wait |\n| **[FIX]** | Type gaps, missing error handling, test gaps, slop | Report → wait |\n| **[AUTO]** | Unused imports, dead code, console.log, typos | Fix immediately |\n| **[CONSIDER]** | Refactors, style opinions, nice-to-have | Mention only |\n\n### AUTO Criteria (all must be true)\n\n- Zero risk of breaking behavior\n- <5 seconds to fix\n- No judgment call needed\n\n**AUTO examples:**\n- Unused imports/variables\n- Trailing whitespace\n- Console.log (unless intentional)\n- Dead/unreachable code\n- Obvious typos in comments/strings\n\n**NOT AUTO (needs confirmation):**\n- Removing \"unused\" function (might be used elsewhere)\n- Type changes (might change behavior)\n- Any logic change\n- AI slop removal (might be intentional)\n\n## Project-Specific Checks\n\n**Always ask these questions during review:**\n\n### Can this be simpler?\n- Is there unnecessary abstraction? Could this be done with less code?\n- Are there helpers/utils being created for one-time operations?\n- Over-engineered error handling, feature flags, or backwards-compat shims?\n- Unnecessary wrapper components or HOCs?\n\n### Can we remove any code?\n- Dead code, unused exports, commented-out blocks?\n- Re-exports or barrel files (we don't use barrel files)?\n- Backwards-compatibility hacks like renamed `_vars` or `// removed` comments?\n- Types/interfaces exported but only used in the same file?\n\n### Is it DRY without premature abstraction?\n- Obvious copy-paste of entire functions or large blocks → refactor\n- But 2-3 similar lines are fine — don't abstract too early\n- The wrong abstraction is worse than duplication\n\n### Is it structured correctly?\n- **Colocate page-specific components** next to their page (not in a nested `components/` subfolder — we don't do that in route directories)\n- **General/reusable components** go in `apps/web/components/`\n- **API routes**: One resource per route, not combined data endpoints\n- **Server actions** for mutations, not POST routes\n- **Validation schemas** in separate `.validation.ts` files\n- **Helper functions** at the bottom of files, not the top\n- **All imports** at the top — no mid-file dynamic imports\n- **No barrel files** (index.ts re-exporting everything from a folder)\n\n### Does it follow project patterns? (see @AGENTS.md)\n- GET routes wrapped with `withAuth` or `withEmailAccount`?\n- Response types exported as `Awaited<ReturnType<typeof fn>>`?\n- SWR for client-side data fetching?\n- `LoadingContent` for loading/error states?\n- `useAction` from `next-safe-action/hooks` for form submissions?\n- Zod schemas with `z.infer<typeof schema>` instead of duplicate interfaces?\n- Self-documenting code? Comments explain \"why\" not \"what\"?\n- `logger.trace()` for PII fields?\n- Test changes follow `.claude/skills/testing/SKILL.md`?\n- Tests avoid mocking `@/utils/logger`?\n- If draft-generation prompt, retrieval, routing, or post-processing changed, was `apps/web/utils/ai/reply/draft-attribution.ts` `DRAFT_PIPELINE_VERSION` bumped for analytics?\n\n### Learnings check\n- Did this change teach us something that should be captured in `AGENTS.md` or this review file?\n- Are there patterns that keep coming up that we should document?\n\n## Mindset\n\n**Inheritance Test:** Would I curse the previous author? Understand at 2am?\n\n**Pride Test:** Would I put my name on this?\n\n## Workflow\n\n### Step 0: Determine Scope & Group Files\n\nAuto-detect: conversation changes → staged → current diff\n\n```bash\ngit diff --cached --name-only  # or HEAD\n```\n\n**Group files by area/dependency:**\n```\nBatch 1: apps/web/app/api/agent/* (3 files)\nBatch 2: apps/web/app/(app)/[emailAccountId]/agent/* (related components)\nBatch 3: apps/web/utils/actions/* (2 files)\n```\n\n**Output:** `Found X files in Y batches`\n\n──────────\n\n### Step 1: Create Review Plan (TODO)\n\n**BEFORE reading any file content**, create todo list:\n\n```\n- [ ] Batch 1: API routes (skills, allowed-actions)\n- [ ] Batch 2: agent page components (agent-page, chat, tools)\n- [ ] Batch 3: server actions (agent.ts, agent.validation.ts)\n```\n\nUse `todo_write` to track batches.\n\n──────────\n\n### Step 2: Process Each Batch\n\n**For each batch:**\n\n1. Read diff for batch files only (`git diff --cached -- path/to/files`)\n2. Review & categorize issues\n3. Auto-fix [AUTO] items immediately\n4. Note [BUG]/[FIX]/[CONSIDER] items\n5. Mark batch complete in todos\n\n**Issue format:**\n```\n1. **[BUG]** Race condition in concurrent saves — `src/db.ts:45`\n2. **[FIX]** Missing error boundary — `src/App.tsx:12`\n3. **[CONSIDER]** Extract to custom hook — `src/Form.tsx:34`\n```\n\n**After each batch:**\n```\nBatch 1 done: AUTO: 2 fixed | BUG: 1 | FIX: 2\n```\n\n──────────\n\n### Step 3: Summary & Options (After All Batches)\n\n```\nTotal: BUG: X | FIX: X | CONSIDER: X (auto-fixed: Y)\n\nIssues:\n1. [BUG] ... — `path:line`\n2. [FIX] ... — `path:line`\n\nWhat to fix?\n- a) BUG + FIX [recommended]\n- b) BUG only\n- c) All including CONSIDER\n- d) Custom (e.g., \"1,3\")\n\nI'll assume a) if you don't specify.\n\nLearnings:\n- Any patterns worth adding to AGENTS.md?\n- Any new review checks to add to this file?\n```\n\n**STOP. Wait for selection.**\n\n──────────\n\n### Step 4: Execute Fixes\n\nProcess fixes batch-by-batch (same grouping):\n\n1. Update todo list with selected fixes\n2. For each batch:\n   - Read relevant file(s)\n   - Apply fixes\n   - Mark complete\n3. Run linter if applicable\n\n## Severity Guide\n\n**BUG (Logic/Security):**\n- Business logic errors, wrong conditions\n- Race conditions, data loss\n- Security: injection, XSS, exposed secrets\n- API routes missing auth middleware\n- Null/undefined not handled\n- Edge cases that break\n\n**FIX (Quality):**\n- Type safety gaps, unsafe casts\n- Missing error handling\n- Test coverage gaps\n- AI slop (WHAT comments, unnecessary try/catch, `as any`)\n- Missing validation\n- Combined API routes that should be separate\n- POST routes used for mutations instead of server actions\n- Barrel files / re-export patterns\n\n**CONSIDER (Opinions):**\n- Refactoring opportunities\n- \"I would do it differently\"\n- Performance micro-optimizations\n- Style preferences\n\n## Git Commands\n\n```bash\n# Staged\ngit diff --cached\ngit diff --cached --name-only\n\n# All uncommitted\ngit diff HEAD\ngit diff HEAD --name-only\n```\n\n## Error Handling\n\n| Error | Response |\n|-------|----------|\n| No changes | \"Check git status or specify files\" |\n| File not found | List available, ask to specify |\n| Binary files | Skip, mention in summary |\n| Large file (>10k) | \"Review specific sections?\" |\n","frontmatter":{"name":"review","description":"Review code changes, auto-fix safe issues, and report bugs","disable-model-invocation":true,"disableModelInvocation":true},"isInternal":false,"tokens":1834,"sizeBytes":7317},{"name":"SKILL.md","path":".claude/skills/test-feature/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/test-feature/SKILL.md","title":"test-feature","category":"anthropic-skill","format":"markdown","content":"---\nname: test-feature\ndescription: \"End-to-end feature testing — browser QA, API verification, eval tests, or any combination. Covers browser interactions (via agent-browser CLI), Google Workspace operations (gws CLI), API calls, and LLM eval tests. Can also persist checks as reusable automated tests.\"\ndisable-model-invocation: true\nargument-hint: \"<description of feature to test>\"\n---\n\nArgs: $ARGUMENTS\n\nYou are an end-to-end feature tester for Inbox Zero. Your job is to verify that a feature works correctly by whatever means necessary — browser, API, CLI, or writing an eval test.\n\n## When invoked\n\nThe user will describe a feature to test, or you can infer it from recent code changes. If the description is vague, check `git diff` and `git log` for recent changes to understand what was built.\n\nThe user may point you to an existing worktree, branch, or PR to test against. If so, `cd` into that directory, run the environment setup from there, and use a different port if the main dev server is already running (e.g., `PORT=3001 pnpm dev`).\n\n## Step 0: Environment setup\n\nBefore testing, make sure the local environment is ready. These steps are idempotent — skip any that are already done.\n\n1. **Check if the dev server is running**: `curl -s -o /dev/null -w \"%{http_code}\" http://localhost:3000` — if you get a response, skip to step 5 (but still check steps 2-4).\n2. **Ensure `.env` exists**: If `apps/web/.env` is missing (common in worktrees), try symlinking from a shared location:\n   ```bash\n   ln -sf ~/.inbox-zero/.env apps/web/.env\n   ln -sf ~/.inbox-zero/.env.test apps/web/.env.test  # for eval tests\n   ```\n   If those symlink sources don't exist, ask the user where their env file is.\n3. **Enable required feature flags**: Check `.env.example` for any env vars the feature needs (e.g. `NEXT_PUBLIC_EXTERNAL_API_ENABLED=true`). If any are missing from `apps/web/.env`, add them now. **IMPORTANT**: `NEXT_PUBLIC_*` vars are baked in at build time — if you add one to `.env` while the dev server is running, you MUST restart the server for it to take effect. Do this BEFORE testing, not after. Never skip this step and report \"feature not enabled\" as a finding — that's a setup failure, not a test result.\n4. **Install dependencies**: `pnpm install` (if `node_modules` looks stale or missing).\n5. **Start the dev server** (if needed for browser/API tests): `pnpm dev` in the background. Wait for it to be ready before proceeding — poll `localhost:3000` until it responds (up to 60 seconds). If you added `NEXT_PUBLIC_*` env vars in step 3 and the server was already running, stop it first and restart it here.\n\n### Isolated local browser QA\n\nFor focused visual QA, check for a free port and initialize an isolated environment:\n\n```bash\npnpm dev-setup init --db empty --auth emulate --url localhost --port <port>\npnpm dev-setup dev --skip-init\n```\n\n- Include `--skip-init` on every subsequent `dev-setup dev` or `dev-setup exec` command; omitting it resets the isolated database.\n- Set required feature flags when starting the server, for example `NEXT_PUBLIC_DIGEST_ENABLED=true pnpm dev-setup dev --skip-init`.\n- Run `pnpm install` if `apps/web/node_modules/@inboxzero/*` links point outside the repository or to a deleted checkout.\n- Seed only the state needed for the test and mark onboarding complete to avoid unrelated setup work. Keep temporary auth and seed files under `.context/` and remove them afterward.\n\n## Step 1: Plan the test\n\nBefore doing anything, decide the right testing approach. Often you'll combine multiple:\n\n| What you're testing | Approach |\n|---|---|\n| UI behavior, settings pages, visual changes | Browser QA — interact with the app, take screenshots |\n| Google Workspace integrations (Drive, Calendar, Gmail) | `gws` CLI for data setup + browser for verification |\n| API endpoints | Direct HTTP calls (curl/fetch), possibly via the app's API with an API key |\n| AI/LLM output quality (drafts, categorization, rules) | Eval test — write or run a test in `__tests__/eval/` |\n| Email processing workflows | E2E flow test or browser QA depending on scope |\n\nTell the user your plan in 2-3 sentences before executing. If you need access or credentials you don't have, say so upfront.\n\n## Step 2: Set up test data\n\nCreate whatever test data the feature needs. Examples:\n- **Google Drive**: Use `gws drive files create` to make folders/files, or do it in the browser\n- **Gmail**: Use `gws gmail users messages send` or send a test email through the browser\n- **Calendar**: Use `gws calendar events insert` to create test events\n- **App config**: Use the browser to configure settings (rules, writing style, connected accounts, etc.)\n\nWhen using `gws`, prefer it for data setup since it's faster and more reliable than browser clicks for creating files/folders/events. Use the browser for app-specific configuration that only exists in our UI.\n\n## Step 3: Execute the test\n\n### Browser testing (via `agent-browser` CLI)\nUse the `agent-browser` skill for all browser interactions. The core loop is: open → snapshot → interact → re-snapshot → screenshot.\n\n- **Navigate by direct URL**: `agent-browser click` on sidebar links can be unreliable. Prefer `agent-browser --cdp 9222 open <full-url>`.\n- **Set viewport to 1440x900**: Headless Chrome defaults to a tiny viewport. After connecting, set it via CDP:\n  ```bash\n  TARGET_ID=$(curl -s http://127.0.0.1:9222/json | node -p \"JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).find(t=>t.type==='page'&&!t.url.startsWith('chrome')).id\")\n  node -e \"const d=JSON.stringify({id:1,method:'Emulation.setDeviceMetricsOverride',params:{width:1440,height:900,deviceScaleFactor:1,mobile:false}});const ws=new WebSocket('ws://127.0.0.1:9222/devtools/page/$TARGET_ID');ws.onopen=()=>ws.send(d);ws.onmessage=()=>ws.close();\"\n  ```\n\n#### Interacting with the chat input\nThe chat textarea has `data-testid=\"chat-input\"`. Use:\n```bash\nagent-browser fill \"[data-testid=chat-input]\" \"Your message here\"\nagent-browser press Enter                          # submit\nsleep 15-30                                        # wait for AI response\nagent-browser screenshot /tmp/result.png\n```\nKey: `fill` and `type` require a **selector** as the first arg (CSS selector or `@ref`). Never call `type \"some text\"` without a selector — that's `keyboard type` (different command). When a CSS selector matches multiple elements, use `agent-browser snapshot` to get unique `@ref` identifiers.\n- Navigate the app as a user would\n- Take a screenshot at every meaningful step — the user wants to see what the UI looks like\n- Pay special attention to: loading states, error states, empty states, success confirmations\n- If testing a flow (e.g., email → rule → draft), wait for async operations to complete before checking results\n- Always `agent-browser close` when done to clean up\n\n#### App route reference\n- Assistant chat: `/<emailAccountId>/assistant`\n- Assistant rules: `/<emailAccountId>/automation`\n- Assistant settings: `/<emailAccountId>/automation?tab=settings`\n- Bulk unsubscribe: `/<emailAccountId>/bulk-unsubscribe`\n- Settings: `/settings`\n\n#### Browser authentication\n\nThe app requires OAuth login. agent-browser can't complete OAuth, so you need a Chrome profile with an existing logged-in session.\n\n**Preferred approach: headless Chrome with a saved profile**\n\nThe user should have a dedicated Chrome profile directory with a logged-in session (stored outside the repo, e.g. `~/.chrome-debug-inbox-zero`). Check the user's auto-memory for the profile path. Then launch Chrome headless and connect:\n\n```bash\n# 1. Check if CDP is already running\ncurl -s http://127.0.0.1:9222/json/version\n\n# 2. If not, launch Chrome headless with the saved profile\n\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\" \\\n  --headless=new \\\n  --remote-debugging-port=9222 \\\n  --user-data-dir=\"$HOME/.chrome-debug-<name>\" &>/dev/null &\nsleep 3\n\n# 3. Connect agent-browser\nagent-browser close\ncurl -s -X PUT \"http://127.0.0.1:9222/json/new?about:blank\" > /dev/null\nsleep 2\nagent-browser --cdp 9222 open http://localhost:3000/automation\n```\n\nThis runs entirely in the background — the user doesn't need to do anything.\n\n**Important caveats:**\n- Chrome won't allow two instances with the same `--user-data-dir` — kill any existing debug Chrome before launching.\n- If auth cookies have expired, the user needs to launch Chrome **headed** (without `--headless=new`) once to re-login via OAuth, then you can go back to headless.\n- Google OAuth blocks agent-browser's built-in Chromium (\"This browser or app may not be secure\") — must use real Chrome.\n- `agent-browser` may attach to `chrome://` internal pages — close those via `agent-browser close` before connecting.\n\n**Fallback options:**\n1. **Connect to user's running Chrome via CDP**: If the user already has Chrome open with `--remote-debugging-port=9222`, just use `agent-browser --cdp 9222`.\n2. **Headed mode with profile**: Use `agent-browser --headed --profile <path>` to open a visible Chrome window.\n3. **State file**: After signing in, save with `agent-browser state save ./auth.json` and reload later with `agent-browser --state ./auth.json`. Note: state files can expire.\n\n### API testing\n- Get a real API key from the UI first (Settings → API Keys) — screenshot the process. **Do not test with fake or dummy API keys**; auth errors mask whether the actual feature works.\n- Configure the CLI/client with the real key, then make real API calls and verify the responses show the expected data.\n- Check both success and error cases.\n\n### Eval testing\n- If the right approach is an eval test, check `__tests__/eval/` for existing tests that cover similar ground\n- Follow the eval test template in `.claude/skills/testing/eval.md`\n- Use `describeEvalMatrix` for cross-model comparison when relevant\n- Use `judgeMultiple` with appropriate `CRITERIA` for subjective outputs\n- Run with `pnpm test-ai eval/<test-name>`\n\n### Hybrid approaches\nOften the best test combines approaches. For example:\n- Use `gws` to create a Google Drive folder with a test PDF\n- Use the browser to configure the feature to use that folder\n- Trigger the feature (send an email, start a chat, etc.)\n- Verify the result in both the UI (screenshot) and via API/database\n\n## Step 4: Report results\n\n**An error means the test failed.** Do not report success if any step produced an error, even if the error seems like a configuration issue. Either fix the configuration and retry, or report the failure clearly.\n\nGive a clear pass/fail summary:\n- What was tested\n- What worked\n- What failed — with screenshots and the actual error\n- What you did to try to fix it\n\nAlways include screenshots — even for passing tests. The user wants to see what the UI looks like.\n\n## Step 5: Persist (if appropriate)\n\nAfter testing, ask the user if this should become a reusable test. Choose the\nsmallest automated boundary that exercises the behavior:\n\n1. **Emulated Playwright test** — for deterministic browser behavior that can\n   run without third-party credentials. Add it under\n   `apps/web/__tests__/playwright/emulated/<area>/` and follow\n   `apps/web/__tests__/playwright/README.md` and the existing fixture patterns.\n\n2. **Real-provider E2E flow** — for Gmail or Outlook delivery, webhooks,\n   provider labels, drafts, or other production-path behavior. Add it under\n   `apps/web/__tests__/e2e/flows/` without replacing provider operations with\n   emulator or database shortcuts.\n\n3. **Eval test** — if the test is about AI output quality, write a proper eval\n   test in `apps/web/__tests__/eval/` that can be run with `pnpm test-ai`.\n\nDon't persist trivial one-off checks (like \"does this page load\"). Persist tests that verify important behavior someone might break later.\n\n## Tool reference\n\n### gws CLI (Google Workspace)\n```bash\n# Create a Drive folder\ngws drive files create --json '{\"name\": \"Test Folder\", \"mimeType\": \"application/vnd.google-apps.folder\"}'\n\n# Upload a file to a folder\ngws drive files create --json '{\"name\": \"test.pdf\", \"parents\": [\"FOLDER_ID\"]}' --upload ./test.pdf\n\n# List Drive files\ngws drive files list --params '{\"q\": \"name contains '\\''test'\\''\", \"pageSize\": 10}'\n\n# Send a Gmail message\ngws gmail users messages send --params '{\"userId\": \"me\"}' --json '{\"raw\": \"BASE64_ENCODED_MESSAGE\"}'\n\n# Create a calendar event\ngws calendar events insert --params '{\"calendarId\": \"primary\"}' --json '{\"summary\": \"Test Event\", \"start\": {\"dateTime\": \"...\"}, \"end\": {\"dateTime\": \"...\"}}'\n```\n\n### Eval test utilities\n- `describeEvalMatrix(name, fn)` — run across models\n- `createEvalReporter()` — track pass/fail\n- `judgeMultiple({ input, output, criteria })` — LLM-as-judge\n- `CRITERIA.*` — ACCURACY, COMPLETENESS, TONE, CONCISENESS, NO_HALLUCINATION, CORRECT_FORMAT\n\n### Existing QA infrastructure\n- Emulated browser tests: `apps/web/__tests__/playwright/emulated/`\n- Real-provider E2E tests: `apps/web/__tests__/e2e/flows/`\n- Eval tests: `apps/web/__tests__/eval/`\n","frontmatter":{"name":"test-feature","description":"End-to-end feature testing — browser QA, API verification, eval tests, or any combination. Covers browser interactions (via agent-browser CLI), Google Workspace operations (gws CLI), API calls, and LLM eval tests. Can also persist checks as reusable automated tests.","disable-model-invocation":true,"argument-hint":"<description of feature to test>","disableModelInvocation":true},"isInternal":false,"tokens":3163,"sizeBytes":13034},{"name":"e2e.md","path":".claude/skills/testing/e2e.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/e2e.md","title":"Testing Skill","category":"anthropic-skill","format":"markdown","content":"# Testing Skill\n\nPath: `.claude/skills/testing/e2e.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/e2e.md)","tokens":300,"sizeBytes":173},{"name":"eval.md","path":".claude/skills/testing/eval.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/eval.md","title":"Testing Skill","category":"anthropic-skill","format":"markdown","content":"# Testing Skill\n\nPath: `.claude/skills/testing/eval.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/eval.md)","tokens":300,"sizeBytes":175},{"name":"integration.md","path":".claude/skills/testing/integration.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/integration.md","title":"Testing Skill","category":"anthropic-skill","format":"markdown","content":"# Testing Skill\n\nPath: `.claude/skills/testing/integration.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/integration.md)","tokens":300,"sizeBytes":189},{"name":"llm.md","path":".claude/skills/testing/llm.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/llm.md","title":"Testing Skill","category":"anthropic-skill","format":"markdown","content":"# Testing Skill\n\nPath: `.claude/skills/testing/llm.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/llm.md)","tokens":300,"sizeBytes":173},{"name":"SKILL.md","path":".claude/skills/testing/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/SKILL.md","title":"testing","category":"anthropic-skill","format":"markdown","content":"---\nname: testing\ndescription: Guidelines for testing the application with Vitest, including unit tests, integration tests (emulator), AI tests, and eval suites for LLM features\n---\n# Testing\n\nAll testing guidance lives in this directory. Read the relevant file for your task:\n\n| Type | File | When to use |\n|------|------|-------------|\n| Unit tests | [unit.md](unit.md) | Framework setup, mocks, colocated tests |\n| Writing tests | [write-tests.md](write-tests.md) | What to test, what to skip, workflow |\n| LLM tests | [llm.md](llm.md) | Tests that call real LLMs (`pnpm test-ai`) |\n| Eval suite | [eval.md](eval.md) | Cross-model comparison, LLM-as-judge |\n| Integration | [integration.md](integration.md) | Emulator-backed tests (`pnpm test-integration`) |\n| Database | `apps/web/__tests__/db/README.md` | Real Postgres, for unique constraints and `updateMany` count guards (`pnpm test-db`) |\n| E2E tests | [e2e.md](e2e.md) | Real email workflow tests from inbox-zero-e2e repo |\n\nPrefer behavior-focused assertions; avoid freezing prompt copy or internal call shapes unless those exact values are the contract under test.\n\n## Quick Commands\n\n```bash\npnpm test path/to/file.test.ts       # Single unit test\npnpm test                            # All unit tests\npnpm test-integration                # Integration tests (emulator)\npnpm test-db                         # Database tests (needs DATABASE_URL on a throwaway db)\npnpm test-ai ai-regression/your-feature  # Live AI regression test\nEVAL_MODELS=all pnpm test-ai eval/your-feature  # Eval across models\n```\n","frontmatter":{"name":"testing","description":"Guidelines for testing the application with Vitest, including unit tests, integration tests (emulator), AI tests, and eval suites for LLM features"},"isInternal":false,"tokens":384,"sizeBytes":1566},{"name":"unit.md","path":".claude/skills/testing/unit.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/unit.md","title":"Testing Skill","category":"anthropic-skill","format":"markdown","content":"# Testing Skill\n\nPath: `.claude/skills/testing/unit.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/unit.md)","tokens":300,"sizeBytes":175},{"name":"write-tests.md","path":".claude/skills/testing/write-tests.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/write-tests.md","title":"Testing Skill","category":"anthropic-skill","format":"markdown","content":"# Testing Skill\n\nPath: `.claude/skills/testing/write-tests.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/write-tests.md)","tokens":300,"sizeBytes":189},{"name":"SKILL.md","path":".claude/skills/ui-components/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/ui-components/SKILL.md","title":"ui-components","category":"anthropic-skill","format":"markdown","content":"---\nname: ui-components\ndescription: UI component and styling guidelines using Shadcn UI, Radix UI, and Tailwind\n---\n# UI Components and Styling\n\n## UI Framework\n- Use Shadcn UI and Tailwind for components and styling\n- Implement responsive design with Tailwind CSS using a mobile-first approach\n- Use `next/image` package for images\n\n## Install new Shadcn components\n\n```sh\npnpm dlx shadcn@latest add COMPONENT\n```\n\nExample:\n\n```sh\npnpm dlx shadcn@latest add progress\n```\n\n## Data Fetching with SWR\nFor API get requests to server use the `swr` package:\n\n```typescript\nconst searchParams = useSearchParams();\nconst page = searchParams.get(\"page\") || \"1\";\nconst { data, isLoading, error } = useSWR<PlanHistoryResponse>(\n  `/api/user/planned/history?page=${page}`\n);\n```\n\n## Loading Components\nUse the `LoadingContent` component to handle loading states:\n\n```tsx\n<Card>\n  <LoadingContent loading={isLoading} error={error}>\n    {data && <MyComponent data={data} />}\n  </LoadingContent>\n</Card>\n```\n\n## Form Components\n### Text Inputs\n```tsx\n<Input\n  type=\"email\"\n  name=\"email\"\n  label=\"Email\"\n  registerProps={register(\"email\", { required: true })}\n  error={errors.email}\n/>\n```\n\n### Text Area\n```tsx\n<Input\n  type=\"text\"\n  autosizeTextarea\n  rows={3}\n  name=\"message\"\n  placeholder=\"Paste in email content\"\n  registerProps={register(\"message\", { required: true })}\n  error={errors.message}\n/>\n```\n","frontmatter":{"name":"ui-components","description":"UI component and styling guidelines using Shadcn UI, Radix UI, and Tailwind"},"isInternal":false,"tokens":361,"sizeBytes":1396},{"name":"SKILL.md","path":".claude/skills/update-packages/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/update-packages/SKILL.md","title":"update-packages","category":"anthropic-skill","format":"markdown","content":"---\nname: update-packages\ndescription: Update workspace packages while respecting the repo's pinned package list in .ncurc.cjs. Use when the user asks to update dependencies or refresh package versions.\n---\n\n# Update Packages\n\nUse this workflow when updating dependencies in this repo.\n\n## Steps\n\n1. Check the pinned package list in `.ncurc.cjs`. Do not upgrade packages listed there.\n2. Keep the repo on Node 24. If you change Node runtime settings, update `.nvmrc`, `engines.node`, `@types/node`, Dockerfiles, and CI together.\n3. Update manifests across the workspace:\n\n```sh\npnpm dlx npm-check-updates -u -ws\n```\n\n4. Refresh the lockfile and install updated packages:\n\n```sh\npnpm install\n```\n\n5. Verify the update:\n\n```sh\npnpm test\npnpm lint\n```\n\n## Notes\n\n- Pin registry `dependencies`, `devDependencies`, and `optionalDependencies` to exact versions. Preserve supported `peerDependencies` ranges in public packages: peers describe consumer compatibility, not lockfile reproducibility. For example, keep the email editor's React and React DOM peers at `>=19` unless its actual compatibility requirements change.\n- `npm-check-updates` reads `.ncurc.cjs`, so the reject list is applied during the manifest update.\n- `pnpm install` may also bump the root `packageManager` field and regenerate `pnpm-lock.yaml`.\n- Do not run `pnpm dev` or `pnpm build` unless the user explicitly asks.\n- Keep `@hookform/resolvers` in the `.ncurc.cjs` reject list and pinned to `4.1.0` while `apps/web` remains on `zod@3.25.76`. The `5.x` resolver line imports `zod/v4/core`, which has caused local Next.js/Turbopack resolution failures even though the app code still uses Zod 3.\n","frontmatter":{"name":"update-packages","description":"Update workspace packages while respecting the repo's pinned package list in .ncurc.cjs. Use when the user asks to update dependencies or refresh package versions."},"isInternal":false,"tokens":412,"sizeBytes":1662},{"name":"SKILL.md","path":".claude/skills/wait/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/wait/SKILL.md","title":"wait","category":"anthropic-skill","format":"markdown","content":"---\nname: wait\ndescription: Pause execution for a user-specified duration\ndisable-model-invocation: true\n---\n\nwait X seconds/minutes (user will provide input). use `sleep` command. DONT do it in background\n","frontmatter":{"name":"wait","description":"Pause execution for a user-specified duration","disable-model-invocation":true,"disableModelInvocation":true},"isInternal":false,"tokens":48,"sizeBytes":206},{"name":"SKILL.md","path":".claude/skills/write-tests/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/write-tests/SKILL.md","title":"write-tests","category":"anthropic-skill","format":"markdown","content":"---\nname: write-tests\ndescription: Write focused unit tests for backend and utility logic\ndisable-model-invocation: true\n---\nRead and follow `.claude/skills/testing/write-tests.md`.\n","frontmatter":{"name":"write-tests","description":"Write focused unit tests for backend and utility logic","disable-model-invocation":true,"disableModelInvocation":true},"isInternal":false,"tokens":39,"sizeBytes":182},{"name":"openai.yaml","path":"clawhub/inbox-zero-api/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/clawhub/inbox-zero-api/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"# Agents Skill\n\nPath: `clawhub/inbox-zero-api/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/clawhub/inbox-zero-api/agents/openai.yaml)","tokens":300,"sizeBytes":196},{"name":"cli-reference.md","path":"clawhub/inbox-zero-api/references/cli-reference.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/clawhub/inbox-zero-api/references/cli-reference.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# References Skill\n\nPath: `clawhub/inbox-zero-api/references/cli-reference.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/clawhub/inbox-zero-api/references/cli-reference.md)","tokens":300,"sizeBytes":218},{"name":"SKILL.md","path":"clawhub/inbox-zero-api/SKILL.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/clawhub/inbox-zero-api/SKILL.md","title":"inbox-zero-api","category":"anthropic-skill","format":"markdown","content":"---\nname: inbox-zero-api\ndescription: Use the Inbox Zero API CLI to inspect the live API schema, list and manage automation rules, and read inbox analytics through the public API. Use this when a task involves Inbox Zero rules, stats, or API-driven automation and can be solved through the CLI instead of browser interaction.\nhomepage: https://www.getinboxzero.com/api-reference/cli\nmetadata: { \"openclaw\": { \"skillKey\": \"inboxZeroApi\", \"requires\": { \"bins\": [\"inbox-zero-api\"], \"env\": [\"INBOX_ZERO_API_KEY\"] }, \"primaryEnv\": \"INBOX_ZERO_API_KEY\", \"install\": [ { \"id\": \"node\", \"kind\": \"node\", \"package\": \"@inbox-zero/api\", \"bins\": [\"inbox-zero-api\"], \"label\": \"Install Inbox Zero API CLI (npm)\" } ] } }\n---\n\n# Inbox Zero API CLI\n\nUse this skill when the task is to inspect or change Inbox Zero state through the public API.\n\n## Workflow\n\n1. Prefer `--json` so the output is stable and machine-readable.\n2. For authenticated commands (`rules`, `stats`, etc.), keep credentials in `INBOX_ZERO_API_KEY` or OpenClaw skill config. Avoid passing API keys as CLI flags unless there is no alternative.\n3. Before creating or replacing a rule body, fetch the live schema with `inbox-zero-api openapi --json` (no API key required).\n4. For create and update flows, write JSON into a workspace file or pipe it on stdin.\n5. Treat `rules update` as a full replacement. Read the current rule first if you only intend to change part of it.\n\n## Quick Start\n\n```bash\ninbox-zero-api rules list --json\ninbox-zero-api stats by-period --period week --json\ninbox-zero-api openapi --json\n```\n\nIf the CLI is not installed yet, install it with the OpenClaw installer or run `npm install -g @inbox-zero/api`.\n\n## Cursor\n\nSet `INBOX_ZERO_API_KEY` when using authenticated commands (`rules`, `stats`, etc.); `openapi --json` works without a key. Use shell profile, Cursor env, or a local env file—never commit keys. Install: `npm install -g @inbox-zero/api` or `npx @inbox-zero/api`.\n\n## OpenClaw Config\n\nSet the API key in `~/.openclaw/openclaw.json` under `skills.entries.inboxZeroApi.apiKey`, or export `INBOX_ZERO_API_KEY` in the host environment.\n\nUse `INBOX_ZERO_BASE_URL` or `inbox-zero-api config set base-url <url>` only for self-hosted or nonstandard deployments.\n\n## Reference\n\nFor exact command patterns and a safe mutation flow, read `references/cli-reference.md`.\n","frontmatter":{"name":"inbox-zero-api","description":"Use the Inbox Zero API CLI to inspect the live API schema, list and manage automation rules, and read inbox analytics through the public API. Use this when a task involves Inbox Zero rules, stats, or API-driven automation and can be solved through the CLI instead of browser interaction.","homepage":"https://www.getinboxzero.com/api-reference/cli","metadata":{"openclaw":{"skillKey":"inboxZeroApi","requires":{"bins":["inbox-zero-api"],"env":["INBOX_ZERO_API_KEY"]},"primaryEnv":"INBOX_ZERO_API_KEY","install":[{"id":"node","kind":"node","package":"@inbox-zero/api","bins":["inbox-zero-api"],"label":"Install Inbox Zero API CLI (npm)"}]}}},"isInternal":false,"tokens":579,"sizeBytes":2350},{"name":"package.json","path":"packages/api/package.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/package.json","title":"Api Skill","category":"anthropic-skill","format":"json","content":"# Api Skill\n\nPath: `packages/api/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/package.json)","tokens":300,"sizeBytes":161},{"name":"tsconfig.json","path":"packages/api/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/tsconfig.json","title":"Api Skill","category":"anthropic-skill","format":"json","content":"# Api Skill\n\nPath: `packages/api/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/tsconfig.json)","tokens":300,"sizeBytes":163},{"name":"package.json","path":"packages/cli/package.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/package.json","title":"Cli Skill","category":"anthropic-skill","format":"json","content":"# Cli Skill\n\nPath: `packages/cli/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/package.json)","tokens":300,"sizeBytes":161},{"name":"tsconfig.json","path":"packages/cli/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/tsconfig.json","title":"Cli Skill","category":"anthropic-skill","format":"json","content":"# Cli Skill\n\nPath: `packages/cli/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/tsconfig.json)","tokens":300,"sizeBytes":163},{"name":"package.json","path":"packages/image-proxy/package.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/image-proxy/package.json","title":"Image-proxy Skill","category":"anthropic-skill","format":"json","content":"# Image-proxy Skill\n\nPath: `packages/image-proxy/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/image-proxy/package.json)","tokens":300,"sizeBytes":185},{"name":"tsconfig.json","path":"packages/image-proxy/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/image-proxy/tsconfig.json","title":"Image-proxy Skill","category":"anthropic-skill","format":"json","content":"# Image-proxy Skill\n\nPath: `packages/image-proxy/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/image-proxy/tsconfig.json)","tokens":300,"sizeBytes":187},{"name":"package.json","path":"packages/loops/package.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/package.json","title":"Loops Skill","category":"anthropic-skill","format":"json","content":"# Loops Skill\n\nPath: `packages/loops/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/package.json)","tokens":300,"sizeBytes":167},{"name":"tsconfig.json","path":"packages/loops/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/tsconfig.json","title":"Loops Skill","category":"anthropic-skill","format":"json","content":"# Loops Skill\n\nPath: `packages/loops/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/tsconfig.json)","tokens":300,"sizeBytes":169},{"name":"package.json","path":"packages/resend/package.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/package.json","title":"Resend Skill","category":"anthropic-skill","format":"json","content":"# Resend Skill\n\nPath: `packages/resend/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/package.json)","tokens":300,"sizeBytes":170},{"name":"tsconfig.json","path":"packages/resend/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/tsconfig.json","title":"Resend Skill","category":"anthropic-skill","format":"json","content":"# Resend Skill\n\nPath: `packages/resend/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/tsconfig.json)","tokens":300,"sizeBytes":172},{"name":"package.json","path":"packages/scheduling/package.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/scheduling/package.json","title":"Scheduling Skill","category":"anthropic-skill","format":"json","content":"# Scheduling Skill\n\nPath: `packages/scheduling/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/scheduling/package.json)","tokens":300,"sizeBytes":182},{"name":"tsconfig.json","path":"packages/scheduling/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/scheduling/tsconfig.json","title":"Scheduling Skill","category":"anthropic-skill","format":"json","content":"# Scheduling Skill\n\nPath: `packages/scheduling/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/scheduling/tsconfig.json)","tokens":300,"sizeBytes":184},{"name":"package.json","path":"packages/tinybird-ai-analytics/package.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/package.json","title":"Tinybird-ai-analytics Skill","category":"anthropic-skill","format":"json","content":"# Tinybird-ai-analytics Skill\n\nPath: `packages/tinybird-ai-analytics/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/package.json)","tokens":300,"sizeBytes":215},{"name":"tsconfig.json","path":"packages/tinybird-ai-analytics/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/tsconfig.json","title":"Tinybird-ai-analytics Skill","category":"anthropic-skill","format":"json","content":"# Tinybird-ai-analytics Skill\n\nPath: `packages/tinybird-ai-analytics/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/tsconfig.json)","tokens":300,"sizeBytes":217},{"name":"package.json","path":"packages/tinybird/package.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/package.json","title":"Tinybird Skill","category":"anthropic-skill","format":"json","content":"# Tinybird Skill\n\nPath: `packages/tinybird/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/package.json)","tokens":300,"sizeBytes":176},{"name":"tinybird.config.json","path":"packages/tinybird/project/tinybird.config.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/project/tinybird.config.json","title":"Project Skill","category":"anthropic-skill","format":"json","content":"# Project Skill\n\nPath: `packages/tinybird/project/tinybird.config.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/project/tinybird.config.json)","tokens":300,"sizeBytes":207},{"name":"tsconfig.json","path":"packages/tinybird/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/tsconfig.json","title":"Tinybird Skill","category":"anthropic-skill","format":"json","content":"# Tinybird Skill\n\nPath: `packages/tinybird/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/tsconfig.json)","tokens":300,"sizeBytes":178},{"name":"base.json","path":"packages/tsconfig/base.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/base.json","title":"Tsconfig Skill","category":"anthropic-skill","format":"json","content":"# Tsconfig Skill\n\nPath: `packages/tsconfig/base.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/base.json)","tokens":300,"sizeBytes":170},{"name":"nextjs.json","path":"packages/tsconfig/nextjs.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/nextjs.json","title":"Tsconfig Skill","category":"anthropic-skill","format":"json","content":"# Tsconfig Skill\n\nPath: `packages/tsconfig/nextjs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/nextjs.json)","tokens":300,"sizeBytes":174},{"name":"package.json","path":"packages/tsconfig/package.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/package.json","title":"Tsconfig Skill","category":"anthropic-skill","format":"json","content":"# Tsconfig Skill\n\nPath: `packages/tsconfig/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tsconfig/package.json)","tokens":300,"sizeBytes":176},{"name":"e2e-testing.mdc","path":".cursor/rules/e2e-testing.mdc","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/e2e-testing.mdc","title":"Cursor Rule: e2e-testing","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: e2e-testing\n\nPath: `.cursor/rules/e2e-testing.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/e2e-testing.mdc)","tokens":300,"sizeBytes":184},{"name":"cleaner.mdc","path":".cursor/rules/features/cleaner.mdc","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/cleaner.mdc","title":"Cursor Rule: cleaner","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: cleaner\n\nPath: `.cursor/rules/features/cleaner.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/cleaner.mdc)","tokens":300,"sizeBytes":190},{"name":"delayed-actions.mdc","path":".cursor/rules/features/delayed-actions.mdc","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/delayed-actions.mdc","title":"Cursor Rule: delayed-actions","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: delayed-actions\n\nPath: `.cursor/rules/features/delayed-actions.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/delayed-actions.mdc)","tokens":300,"sizeBytes":214},{"name":"digest.mdc","path":".cursor/rules/features/digest.mdc","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/digest.mdc","title":"Cursor Rule: digest","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: digest\n\nPath: `.cursor/rules/features/digest.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/digest.mdc)","tokens":300,"sizeBytes":187},{"name":"knowledge.mdc","path":".cursor/rules/features/knowledge.mdc","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/knowledge.mdc","title":"Cursor Rule: knowledge","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: knowledge\n\nPath: `.cursor/rules/features/knowledge.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/knowledge.mdc)","tokens":300,"sizeBytes":196},{"name":"reply-memory.mdc","path":".cursor/rules/features/reply-memory.mdc","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/reply-memory.mdc","title":"Cursor Rule: reply-memory","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: reply-memory\n\nPath: `.cursor/rules/features/reply-memory.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/reply-memory.mdc)","tokens":300,"sizeBytes":205},{"name":"schedule.mdc","path":".cursor/rules/features/schedule.mdc","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/schedule.mdc","title":"Cursor Rule: schedule","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: schedule\n\nPath: `.cursor/rules/features/schedule.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/features/schedule.mdc)","tokens":300,"sizeBytes":193},{"name":"posthog-feature-flags.mdc","path":".cursor/rules/posthog-feature-flags.mdc","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/posthog-feature-flags.mdc","title":"Cursor Rule: posthog-feature-flags","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: posthog-feature-flags\n\nPath: `.cursor/rules/posthog-feature-flags.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/posthog-feature-flags.mdc)","tokens":300,"sizeBytes":214},{"name":"task-list.mdc","path":".cursor/rules/task-list.mdc","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/task-list.mdc","title":"Cursor Rule: task-list","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: task-list\n\nPath: `.cursor/rules/task-list.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/task-list.mdc)","tokens":300,"sizeBytes":178},{"name":"ultracite.mdc","path":".cursor/rules/ultracite.mdc","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/ultracite.mdc","title":"Cursor Rule: ultracite","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: ultracite\n\nPath: `.cursor/rules/ultracite.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor/rules/ultracite.mdc)","tokens":300,"sizeBytes":178},{"name":"authenticated-session.sh","path":".claude/skills/agent-browser/templates/authenticated-session.sh","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/authenticated-session.sh","title":"Claude Directive: authenticated-session.sh","category":"claude-rule","format":"markdown","content":"# Claude Directive: authenticated-session.sh\n\nPath: `.claude/skills/agent-browser/templates/authenticated-session.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/authenticated-session.sh)","tokens":300,"sizeBytes":270},{"name":"capture-workflow.sh","path":".claude/skills/agent-browser/templates/capture-workflow.sh","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/capture-workflow.sh","title":"Claude Directive: capture-workflow.sh","category":"claude-rule","format":"markdown","content":"# Claude Directive: capture-workflow.sh\n\nPath: `.claude/skills/agent-browser/templates/capture-workflow.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/capture-workflow.sh)","tokens":300,"sizeBytes":255},{"name":"form-automation.sh","path":".claude/skills/agent-browser/templates/form-automation.sh","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/form-automation.sh","title":"Claude Directive: form-automation.sh","category":"claude-rule","format":"markdown","content":"# Claude Directive: form-automation.sh\n\nPath: `.claude/skills/agent-browser/templates/form-automation.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/templates/form-automation.sh)","tokens":300,"sizeBytes":252},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# Claude Agent Guidelines & System Prompt\n\nPath: `CLAUDE.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/CLAUDE.md)","tokens":300,"sizeBytes":159},{"name":"plugin.json","path":".cursor-plugin/plugin.json","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor-plugin/plugin.json","title":"cursor-plugin Plugin Manifest","category":"plugin-manifest","format":"json","content":"# cursor-plugin Plugin Manifest\n\nPath: `.cursor-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.cursor-plugin/plugin.json)","tokens":300,"sizeBytes":183},{"name":"README.md","path":"packages/api/README.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/README.md","title":"api Documentation","category":"plugin-manifest","format":"markdown","content":"# api Documentation\n\nPath: `packages/api/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/api/README.md)","tokens":300,"sizeBytes":163},{"name":"README.md","path":"packages/cli/README.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/README.md","title":"cli Documentation","category":"plugin-manifest","format":"markdown","content":"# cli Documentation\n\nPath: `packages/cli/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/cli/README.md)","tokens":300,"sizeBytes":163},{"name":"README.md","path":"packages/loops/README.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/README.md","title":"loops Documentation","category":"plugin-manifest","format":"markdown","content":"# loops Documentation\n\nPath: `packages/loops/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/loops/README.md)","tokens":300,"sizeBytes":169},{"name":"README.md","path":"packages/resend/README.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/README.md","title":"resend Documentation","category":"plugin-manifest","format":"markdown","content":"# resend Documentation\n\nPath: `packages/resend/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/resend/README.md)","tokens":300,"sizeBytes":172},{"name":"README.md","path":"packages/tinybird-ai-analytics/README.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/README.md","title":"tinybird-ai-analytics Documentation","category":"plugin-manifest","format":"markdown","content":"# tinybird-ai-analytics Documentation\n\nPath: `packages/tinybird-ai-analytics/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird-ai-analytics/README.md)","tokens":300,"sizeBytes":217},{"name":"README.md","path":"packages/tinybird/README.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/README.md","title":"tinybird Documentation","category":"plugin-manifest","format":"markdown","content":"# tinybird Documentation\n\nPath: `packages/tinybird/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/packages/tinybird/README.md)","tokens":300,"sizeBytes":178},{"name":"reviewer.md","path":".claude/agents/reviewer.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/agents/reviewer.md","title":"Subagent: reviewer","category":"subagent-persona","format":"markdown","content":"# Subagent: reviewer\n\nPath: `.claude/agents/reviewer.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/agents/reviewer.md)","tokens":300,"sizeBytes":172},{"name":"code-simplifier.toml","path":".codex/agents/code-simplifier.toml","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/agents/code-simplifier.toml","title":"Codex Directive: code-simplifier.toml","category":"codex-rule","format":"markdown","content":"# Codex Directive: code-simplifier.toml\n\nPath: `.codex/agents/code-simplifier.toml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/agents/code-simplifier.toml)","tokens":300,"sizeBytes":207},{"name":"reviewer.toml","path":".codex/agents/reviewer.toml","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/agents/reviewer.toml","title":"Codex Directive: reviewer.toml","category":"codex-rule","format":"markdown","content":"# Codex Directive: reviewer.toml\n\nPath: `.codex/agents/reviewer.toml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/agents/reviewer.toml)","tokens":300,"sizeBytes":186},{"name":"config.toml","path":".codex/config.toml","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/config.toml","title":"Codex Directive: config.toml","category":"codex-rule","format":"markdown","content":"# Codex Directive: config.toml\n\nPath: `.codex/config.toml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.codex/config.toml)","tokens":300,"sizeBytes":166},{"name":"inbox-zero-api-cli.md","path":"agents/inbox-zero-api-cli.md","rawUrl":"https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/agents/inbox-zero-api-cli.md","title":"Subagent: inbox-zero-api-cli","category":"subagent-persona","format":"markdown","content":"# Subagent: inbox-zero-api-cli\n\nPath: `agents/inbox-zero-api-cli.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/agents/inbox-zero-api-cli.md)","tokens":300,"sizeBytes":186}],"systemPromptSnippet":"<yakaai_skills repo=\"elie222/inbox-zero\">\n<!-- File: AGENTS.md (Tokens: ~300 | Category: root-instruction) -->\n# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/AGENTS.md)\n\n<!-- File: .claude/skills/agent-browser/references/authentication.md (Tokens: ~300 | Category: anthropic-skill) -->\n# References Skill\n\nPath: `.claude/skills/agent-browser/references/authentication.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/authentication.md)\n\n<!-- File: .claude/skills/agent-browser/references/commands.md (Tokens: ~300 | Category: anthropic-skill) -->\n# References Skill\n\nPath: `.claude/skills/agent-browser/references/commands.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/commands.md)\n\n<!-- File: .claude/skills/agent-browser/references/profiling.md (Tokens: ~300 | Category: anthropic-skill) -->\n# References Skill\n\nPath: `.claude/skills/agent-browser/references/profiling.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/profiling.md)\n\n<!-- File: .claude/skills/agent-browser/references/proxy-support.md (Tokens: ~300 | Category: anthropic-skill) -->\n# References Skill\n\nPath: `.claude/skills/agent-browser/references/proxy-support.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/proxy-support.md)\n\n<!-- File: .claude/skills/agent-browser/references/session-management.md (Tokens: ~300 | Category: anthropic-skill) -->\n# References Skill\n\nPath: `.claude/skills/agent-browser/references/session-management.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/session-management.md)\n\n<!-- File: .claude/skills/agent-browser/references/snapshot-refs.md (Tokens: ~300 | Category: anthropic-skill) -->\n# References Skill\n\nPath: `.claude/skills/agent-browser/references/snapshot-refs.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/snapshot-refs.md)\n\n<!-- File: .claude/skills/agent-browser/references/video-recording.md (Tokens: ~300 | Category: anthropic-skill) -->\n# References Skill\n\nPath: `.claude/skills/agent-browser/references/video-recording.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/references/video-recording.md)\n\n<!-- File: .claude/skills/agent-browser/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# agent-browser\n\nPath: `.claude/skills/agent-browser/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/agent-browser/SKILL.md)\n\n<!-- File: .claude/skills/changelog/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# changelog\n\nPath: `.claude/skills/changelog/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/changelog/SKILL.md)\n\n<!-- File: .claude/skills/cloud-dev-environment/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# cloud-dev-environment\n\nPath: `.claude/skills/cloud-dev-environment/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/cloud-dev-environment/SKILL.md)\n\n<!-- File: .claude/skills/code-simplifier/agents/openai.yaml (Tokens: ~300 | Category: anthropic-skill) -->\n# Agents Skill\n\nPath: `.claude/skills/code-simplifier/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/code-simplifier/agents/openai.yaml)\n\n<!-- File: .claude/skills/code-simplifier/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# code-simplifier\n\nPath: `.claude/skills/code-simplifier/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/code-simplifier/SKILL.md)\n\n<!-- File: .claude/skills/create-pr/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# create-pr\n\nPath: `.claude/skills/create-pr/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/create-pr/SKILL.md)\n\n<!-- File: .claude/skills/e2e/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# e2e\n\nPath: `.claude/skills/e2e/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/e2e/SKILL.md)\n\n<!-- File: .claude/skills/environment-variables/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# environment-variables\n\nPath: `.claude/skills/environment-variables/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/environment-variables/SKILL.md)\n\n<!-- File: .claude/skills/explain-changes/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# explain-changes\n\nPath: `.claude/skills/explain-changes/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/explain-changes/SKILL.md)\n\n<!-- File: .claude/skills/fullstack-workflow/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# fullstack-workflow\n\nPath: `.claude/skills/fullstack-workflow/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/fullstack-workflow/SKILL.md)\n\n<!-- File: .claude/skills/llm-test/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# llm-test\n\nPath: `.claude/skills/llm-test/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/llm-test/SKILL.md)\n\n<!-- File: .claude/skills/llm/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# llm\n\nPath: `.claude/skills/llm/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/llm/SKILL.md)\n\n<!-- File: .claude/skills/logging/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# logging\n\nPath: `.claude/skills/logging/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/logging/SKILL.md)\n\n<!-- File: .claude/skills/prisma/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# prisma\n\nPath: `.claude/skills/prisma/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/prisma/SKILL.md)\n\n<!-- File: .claude/skills/project-structure/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# project-structure\n\nPath: `.claude/skills/project-structure/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/project-structure/SKILL.md)\n\n<!-- File: .claude/skills/qa-label/SKILL.md (Tokens: ~88 | Category: anthropic-skill) -->\n---\nname: qa-label\ndescription: Label a PR as ready for QA so the QA server picks it up automatically\n---\n\nTo mark a PR ready for QA, run: `gh pr edit <PR_NUMBER> --add-label \"ready-for-qa\"`\n\nAn automated QA process on the QA server will pick it up within ~60s and run browser tests against the PR branch. New pushes retrigger automatically while the label is present.\n\n<!-- File: .claude/skills/review-ai-prompt-changes/agents/openai.yaml (Tokens: ~300 | Category: anthropic-skill) -->\n# Agents Skill\n\nPath: `.claude/skills/review-ai-prompt-changes/agents/openai.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/review-ai-prompt-changes/agents/openai.yaml)\n\n<!-- File: .claude/skills/review-ai-prompt-changes/SKILL.md (Tokens: ~846 | Category: anthropic-skill) -->\n---\nname: review-ai-prompt-changes\ndescription: Review prompt and tool-description changes in a branch or PR. Use when asked to audit system prompts, prompt builders, tool descriptions, prompt inputs, or nearby evals/tests; summarize what changed; identify guidance that feels eval-shaped or too heavy for product use; and find repeated instructions between the main prompt and tool descriptions.\n---\n\n# Review Prompt Changes\n\nReview prompt-related diffs with a product lens. Focus on what actually changed, whether the guidance belongs in the prompt layer where it was added, and whether any wording is repetitive or overfit to evals.\n\n## Scope\n\n- Default to `main...HEAD` unless the user names a different base.\n- Prioritize runtime files that shape model behavior:\n  - system prompts\n  - prompt builders and prompt fragments\n  - tool descriptions and schema field descriptions\n  - response-formatting instructions\n- Read evals and unit tests only after the runtime diffs so you can infer the intent behind the change without letting the tests define the review.\n\nIn this repo, likely files live under:\n\n- `apps/web/utils/ai/**`\n- `apps/web/utils/ai/assistant/**`\n- `apps/web/__tests__/eval/**`\n- `apps/web/__tests__/**` for prompt-adjacent unit tests\n\n## Workflow\n\n1. Find the changed files with `git diff --name-only main...HEAD`.\n2. Narrow to prompt-relevant files first. Ignore unrelated UI or plumbing unless it changes what reaches the model.\n3. Read diffs with enough context to see the full prompt block or tool description.\n4. Then read nearby tests or evals to understand what failure mode the change is trying to prevent.\n5. Separate your notes into four buckets:\n   - behavior changes\n   - product-helpful prompt guidance\n   - heavy or eval-shaped guidance\n   - repeated guidance across layers\n6. Prefer exact file and line references in the review.\n\n## What To Look For\n\n### Product-helpful changes\n\n- Capability gating that matches real product states or disabled tools\n- Moving provider-specific or tool-specific guidance into the relevant tool description\n- Adding richer tool outputs that support grounded answers\n- Clear write-confirmation or safety rules tied to real UI behavior\n\n### Heavy or eval-shaped changes\n\n- Cross-cutting language added mainly to defend a known eval failure mode\n- Response-policy coaching inside a tool description when it is not tool-local\n- Repeated “treat as evidence,” “state the conflict plainly,” or “do not invent causes” language across multiple prompt layers\n- Tiny wording splits that duplicate long blocks for web vs messaging, provider A vs provider B, or enabled vs disabled states\n- Instructions that read like judging criteria instead of operating guidance\n\n### Repetition to call out\n\nCheck whether the same instruction appears in more than one of these places:\n\n- the system prompt\n- tool descriptions\n- input schema field descriptions\n- formatting blocks\n- tests or eval-driven comments copied into runtime prompt text\n\nTool-local guidance usually belongs in the tool description. Cross-cutting behavior rules usually belong in the main prompt. Flag cases where both layers say the same thing without adding meaning.\n\n## Review Output\n\nUse this structure:\n\n1. `Findings`\n   - findings first, ordered by severity\n   - include file and line references\n   - focus on heaviness, redundancy, or misplaced guidance\n2. `What Changed`\n   - summarize the actual prompt/tool behavior changes\n   - mention tests or evals only as evidence of intent\n3. `Net Read`\n   - say which changes feel product-helpful\n   - say which changes feel eval-shaped\n   - say what the best trim targets are\n\nKeep the review concise, but cover the full prompt story. The user asked for both the diff summary and the judgment call.\n\n## Repo Notes\n\n- Project-specific skills live under `.claude/skills/<skill-name>/SKILL.md`.\n- Match the house style: short frontmatter, concise body, no extra README files.\n- Do not edit prompts by default. This skill is for audit/review unless the user explicitly asks for changes.\n\n<!-- File: .claude/skills/review/SKILL.md (Tokens: ~1834 | Category: anthropic-skill) -->\n---\nname: review\ndescription: Review code changes, auto-fix safe issues, and report bugs\ndisable-model-invocation: true\n---\n\n# review\n\nCode review with craftsman's eye. Auto-fix obvious issues, surface real bugs.\n\nReference @AGENTS.md for project conventions. Apply those patterns as review criteria.\n\n## Critical Rules\n\n1. **AUTO-FIX safe obvious issues** - Don't ask permission for no-brainers\n2. **HUNT FOR BUGS** - Logic errors, edge cases, race conditions first\n3. **WAIT for confirmation** - On BUG/FIX, don't execute until user says \"go\"\n4. **BE CONCISE** - One-line items, choices at END\n5. **USE clickable links** - `path/to/file.ts:123` format only\n\n## Categories\n\n| Category | What | Action |\n|----------|------|--------|\n| **[BUG]** | Logic errors, security, data loss, race conditions | Report → wait |\n| **[FIX]** | Type gaps, missing error handling, test gaps, slop | Report → wait |\n| **[AUTO]** | Unused imports, dead code, console.log, typos | Fix immediately |\n| **[CONSIDER]** | Refactors, style opinions, nice-to-have | Mention only |\n\n### AUTO Criteria (all must be true)\n\n- Zero risk of breaking behavior\n- <5 seconds to fix\n- No judgment call needed\n\n**AUTO examples:**\n- Unused imports/variables\n- Trailing whitespace\n- Console.log (unless intentional)\n- Dead/unreachable code\n- Obvious typos in comments/strings\n\n**NOT AUTO (needs confirmation):**\n- Removing \"unused\" function (might be used elsewhere)\n- Type changes (might change behavior)\n- Any logic change\n- AI slop removal (might be intentional)\n\n## Project-Specific Checks\n\n**Always ask these questions during review:**\n\n### Can this be simpler?\n- Is there unnecessary abstraction? Could this be done with less code?\n- Are there helpers/utils being created for one-time operations?\n- Over-engineered error handling, feature flags, or backwards-compat shims?\n- Unnecessary wrapper components or HOCs?\n\n### Can we remove any code?\n- Dead code, unused exports, commented-out blocks?\n- Re-exports or barrel files (we don't use barrel files)?\n- Backwards-compatibility hacks like renamed `_vars` or `// removed` comments?\n- Types/interfaces exported but only used in the same file?\n\n### Is it DRY without premature abstraction?\n- Obvious copy-paste of entire functions or large blocks → refactor\n- But 2-3 similar lines are fine — don't abstract too early\n- The wrong abstraction is worse than duplication\n\n### Is it structured correctly?\n- **Colocate page-specific components** next to their page (not in a nested `components/` subfolder — we don't do that in route directories)\n- **General/reusable components** go in `apps/web/components/`\n- **API routes**: One resource per route, not combined data endpoints\n- **Server actions** for mutations, not POST routes\n- **Validation schemas** in separate `.validation.ts` files\n- **Helper functions** at the bottom of files, not the top\n- **All imports** at the top — no mid-file dynamic imports\n- **No barrel files** (index.ts re-exporting everything from a folder)\n\n### Does it follow project patterns? (see @AGENTS.md)\n- GET routes wrapped with `withAuth` or `withEmailAccount`?\n- Response types exported as `Awaited<ReturnType<typeof fn>>`?\n- SWR for client-side data fetching?\n- `LoadingContent` for loading/error states?\n- `useAction` from `next-safe-action/hooks` for form submissions?\n- Zod schemas with `z.infer<typeof schema>` instead of duplicate interfaces?\n- Self-documenting code? Comments explain \"why\" not \"what\"?\n- `logger.trace()` for PII fields?\n- Test changes follow `.claude/skills/testing/SKILL.md`?\n- Tests avoid mocking `@/utils/logger`?\n- If draft-generation prompt, retrieval, routing, or post-processing changed, was `apps/web/utils/ai/reply/draft-attribution.ts` `DRAFT_PIPELINE_VERSION` bumped for analytics?\n\n### Learnings check\n- Did this change teach us something that should be captured in `AGENTS.md` or this review file?\n- Are there patterns that keep coming up that we should document?\n\n## Mindset\n\n**Inheritance Test:** Would I curse the previous author? Understand at 2am?\n\n**Pride Test:** Would I put my name on this?\n\n## Workflow\n\n### Step 0: Determine Scope & Group Files\n\nAuto-detect: conversation changes → staged → current diff\n\n```bash\ngit diff --cached --name-only  # or HEAD\n```\n\n**Group files by area/dependency:**\n```\nBatch 1: apps/web/app/api/agent/* (3 files)\nBatch 2: apps/web/app/(app)/[emailAccountId]/agent/* (related components)\nBatch 3: apps/web/utils/actions/* (2 files)\n```\n\n**Output:** `Found X files in Y batches`\n\n──────────\n\n### Step 1: Create Review Plan (TODO)\n\n**BEFORE reading any file content**, create todo list:\n\n```\n- [ ] Batch 1: API routes (skills, allowed-actions)\n- [ ] Batch 2: agent page components (agent-page, chat, tools)\n- [ ] Batch 3: server actions (agent.ts, agent.validation.ts)\n```\n\nUse `todo_write` to track batches.\n\n──────────\n\n### Step 2: Process Each Batch\n\n**For each batch:**\n\n1. Read diff for batch files only (`git diff --cached -- path/to/files`)\n2. Review & categorize issues\n3. Auto-fix [AUTO] items immediately\n4. Note [BUG]/[FIX]/[CONSIDER] items\n5. Mark batch complete in todos\n\n**Issue format:**\n```\n1. **[BUG]** Race condition in concurrent saves — `src/db.ts:45`\n2. **[FIX]** Missing error boundary — `src/App.tsx:12`\n3. **[CONSIDER]** Extract to custom hook — `src/Form.tsx:34`\n```\n\n**After each batch:**\n```\nBatch 1 done: AUTO: 2 fixed | BUG: 1 | FIX: 2\n```\n\n──────────\n\n### Step 3: Summary & Options (After All Batches)\n\n```\nTotal: BUG: X | FIX: X | CONSIDER: X (auto-fixed: Y)\n\nIssues:\n1. [BUG] ... — `path:line`\n2. [FIX] ... — `path:line`\n\nWhat to fix?\n- a) BUG + FIX [recommended]\n- b) BUG only\n- c) All including CONSIDER\n- d) Custom (e.g., \"1,3\")\n\nI'll assume a) if you don't specify.\n\nLearnings:\n- Any patterns worth adding to AGENTS.md?\n- Any new review checks to add to this file?\n```\n\n**STOP. Wait for selection.**\n\n──────────\n\n### Step 4: Execute Fixes\n\nProcess fixes batch-by-batch (same grouping):\n\n1. Update todo list with selected fixes\n2. For each batch:\n   - Read relevant file(s)\n   - Apply fixes\n   - Mark complete\n3. Run linter if applicable\n\n## Severity Guide\n\n**BUG (Logic/Security):**\n- Business logic errors, wrong conditions\n- Race conditions, data loss\n- Security: injection, XSS, exposed secrets\n- API routes missing auth middleware\n- Null/undefined not handled\n- Edge cases that break\n\n**FIX (Quality):**\n- Type safety gaps, unsafe casts\n- Missing error handling\n- Test coverage gaps\n- AI slop (WHAT comments, unnecessary try/catch, `as any`)\n- Missing validation\n- Combined API routes that should be separate\n- POST routes used for mutations instead of server actions\n- Barrel files / re-export patterns\n\n**CONSIDER (Opinions):**\n- Refactoring opportunities\n- \"I would do it differently\"\n- Performance micro-optimizations\n- Style preferences\n\n## Git Commands\n\n```bash\n# Staged\ngit diff --cached\ngit diff --cached --name-only\n\n# All uncommitted\ngit diff HEAD\ngit diff HEAD --name-only\n```\n\n## Error Handling\n\n| Error | Response |\n|-------|----------|\n| No changes | \"Check git status or specify files\" |\n| File not found | List available, ask to specify |\n| Binary files | Skip, mention in summary |\n| Large file (>10k) | \"Review specific sections?\" |\n\n<!-- File: .claude/skills/test-feature/SKILL.md (Tokens: ~3163 | Category: anthropic-skill) -->\n---\nname: test-feature\ndescription: \"End-to-end feature testing — browser QA, API verification, eval tests, or any combination. Covers browser interactions (via agent-browser CLI), Google Workspace operations (gws CLI), API calls, and LLM eval tests. Can also persist checks as reusable automated tests.\"\ndisable-model-invocation: true\nargument-hint: \"<description of feature to test>\"\n---\n\nArgs: $ARGUMENTS\n\nYou are an end-to-end feature tester for Inbox Zero. Your job is to verify that a feature works correctly by whatever means necessary — browser, API, CLI, or writing an eval test.\n\n## When invoked\n\nThe user will describe a feature to test, or you can infer it from recent code changes. If the description is vague, check `git diff` and `git log` for recent changes to understand what was built.\n\nThe user may point you to an existing worktree, branch, or PR to test against. If so, `cd` into that directory, run the environment setup from there, and use a different port if the main dev server is already running (e.g., `PORT=3001 pnpm dev`).\n\n## Step 0: Environment setup\n\nBefore testing, make sure the local environment is ready. These steps are idempotent — skip any that are already done.\n\n1. **Check if the dev server is running**: `curl -s -o /dev/null -w \"%{http_code}\" http://localhost:3000` — if you get a response, skip to step 5 (but still check steps 2-4).\n2. **Ensure `.env` exists**: If `apps/web/.env` is missing (common in worktrees), try symlinking from a shared location:\n   ```bash\n   ln -sf ~/.inbox-zero/.env apps/web/.env\n   ln -sf ~/.inbox-zero/.env.test apps/web/.env.test  # for eval tests\n   ```\n   If those symlink sources don't exist, ask the user where their env file is.\n3. **Enable required feature flags**: Check `.env.example` for any env vars the feature needs (e.g. `NEXT_PUBLIC_EXTERNAL_API_ENABLED=true`). If any are missing from `apps/web/.env`, add them now. **IMPORTANT**: `NEXT_PUBLIC_*` vars are baked in at build time — if you add one to `.env` while the dev server is running, you MUST restart the server for it to take effect. Do this BEFORE testing, not after. Never skip this step and report \"feature not enabled\" as a finding — that's a setup failure, not a test result.\n4. **Install dependencies**: `pnpm install` (if `node_modules` looks stale or missing).\n5. **Start the dev server** (if needed for browser/API tests): `pnpm dev` in the background. Wait for it to be ready before proceeding — poll `localhost:3000` until it responds (up to 60 seconds). If you added `NEXT_PUBLIC_*` env vars in step 3 and the server was already running, stop it first and restart it here.\n\n### Isolated local browser QA\n\nFor focused visual QA, check for a free port and initialize an isolated environment:\n\n```bash\npnpm dev-setup init --db empty --auth emulate --url localhost --port <port>\npnpm dev-setup dev --skip-init\n```\n\n- Include `--skip-init` on every subsequent `dev-setup dev` or `dev-setup exec` command; omitting it resets the isolated database.\n- Set required feature flags when starting the server, for example `NEXT_PUBLIC_DIGEST_ENABLED=true pnpm dev-setup dev --skip-init`.\n- Run `pnpm install` if `apps/web/node_modules/@inboxzero/*` links point outside the repository or to a deleted checkout.\n- Seed only the state needed for the test and mark onboarding complete to avoid unrelated setup work. Keep temporary auth and seed files under `.context/` and remove them afterward.\n\n## Step 1: Plan the test\n\nBefore doing anything, decide the right testing approach. Often you'll combine multiple:\n\n| What you're testing | Approach |\n|---|---|\n| UI behavior, settings pages, visual changes | Browser QA — interact with the app, take screenshots |\n| Google Workspace integrations (Drive, Calendar, Gmail) | `gws` CLI for data setup + browser for verification |\n| API endpoints | Direct HTTP calls (curl/fetch), possibly via the app's API with an API key |\n| AI/LLM output quality (drafts, categorization, rules) | Eval test — write or run a test in `__tests__/eval/` |\n| Email processing workflows | E2E flow test or browser QA depending on scope |\n\nTell the user your plan in 2-3 sentences before executing. If you need access or credentials you don't have, say so upfront.\n\n## Step 2: Set up test data\n\nCreate whatever test data the feature needs. Examples:\n- **Google Drive**: Use `gws drive files create` to make folders/files, or do it in the browser\n- **Gmail**: Use `gws gmail users messages send` or send a test email through the browser\n- **Calendar**: Use `gws calendar events insert` to create test events\n- **App config**: Use the browser to configure settings (rules, writing style, connected accounts, etc.)\n\nWhen using `gws`, prefer it for data setup since it's faster and more reliable than browser clicks for creating files/folders/events. Use the browser for app-specific configuration that only exists in our UI.\n\n## Step 3: Execute the test\n\n### Browser testing (via `agent-browser` CLI)\nUse the `agent-browser` skill for all browser interactions. The core loop is: open → snapshot → interact → re-snapshot → screenshot.\n\n- **Navigate by direct URL**: `agent-browser click` on sidebar links can be unreliable. Prefer `agent-browser --cdp 9222 open <full-url>`.\n- **Set viewport to 1440x900**: Headless Chrome defaults to a tiny viewport. After connecting, set it via CDP:\n  ```bash\n  TARGET_ID=$(curl -s http://127.0.0.1:9222/json | node -p \"JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).find(t=>t.type==='page'&&!t.url.startsWith('chrome')).id\")\n  node -e \"const d=JSON.stringify({id:1,method:'Emulation.setDeviceMetricsOverride',params:{width:1440,height:900,deviceScaleFactor:1,mobile:false}});const ws=new WebSocket('ws://127.0.0.1:9222/devtools/page/$TARGET_ID');ws.onopen=()=>ws.send(d);ws.onmessage=()=>ws.close();\"\n  ```\n\n#### Interacting with the chat input\nThe chat textarea has `data-testid=\"chat-input\"`. Use:\n```bash\nagent-browser fill \"[data-testid=chat-input]\" \"Your message here\"\nagent-browser press Enter                          # submit\nsleep 15-30                                        # wait for AI response\nagent-browser screenshot /tmp/result.png\n```\nKey: `fill` and `type` require a **selector** as the first arg (CSS selector or `@ref`). Never call `type \"some text\"` without a selector — that's `keyboard type` (different command). When a CSS selector matches multiple elements, use `agent-browser snapshot` to get unique `@ref` identifiers.\n- Navigate the app as a user would\n- Take a screenshot at every meaningful step — the user wants to see what the UI looks like\n- Pay special attention to: loading states, error states, empty states, success confirmations\n- If testing a flow (e.g., email → rule → draft), wait for async operations to complete before checking results\n- Always `agent-browser close` when done to clean up\n\n#### App route reference\n- Assistant chat: `/<emailAccountId>/assistant`\n- Assistant rules: `/<emailAccountId>/automation`\n- Assistant settings: `/<emailAccountId>/automation?tab=settings`\n- Bulk unsubscribe: `/<emailAccountId>/bulk-unsubscribe`\n- Settings: `/settings`\n\n#### Browser authentication\n\nThe app requires OAuth login. agent-browser can't complete OAuth, so you need a Chrome profile with an existing logged-in session.\n\n**Preferred approach: headless Chrome with a saved profile**\n\nThe user should have a dedicated Chrome profile directory with a logged-in session (stored outside the repo, e.g. `~/.chrome-debug-inbox-zero`). Check the user's auto-memory for the profile path. Then launch Chrome headless and connect:\n\n```bash\n# 1. Check if CDP is already running\ncurl -s http://127.0.0.1:9222/json/version\n\n# 2. If not, launch Chrome headless with the saved profile\n\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\" \\\n  --headless=new \\\n  --remote-debugging-port=9222 \\\n  --user-data-dir=\"$HOME/.chrome-debug-<name>\" &>/dev/null &\nsleep 3\n\n# 3. Connect agent-browser\nagent-browser close\ncurl -s -X PUT \"http://127.0.0.1:9222/json/new?about:blank\" > /dev/null\nsleep 2\nagent-browser --cdp 9222 open http://localhost:3000/automation\n```\n\nThis runs entirely in the background — the user doesn't need to do anything.\n\n**Important caveats:**\n- Chrome won't allow two instances with the same `--user-data-dir` — kill any existing debug Chrome before launching.\n- If auth cookies have expired, the user needs to launch Chrome **headed** (without `--headless=new`) once to re-login via OAuth, then you can go back to headless.\n- Google OAuth blocks agent-browser's built-in Chromium (\"This browser or app may not be secure\") — must use real Chrome.\n- `agent-browser` may attach to `chrome://` internal pages — close those via `agent-browser close` before connecting.\n\n**Fallback options:**\n1. **Connect to user's running Chrome via CDP**: If the user already has Chrome open with `--remote-debugging-port=9222`, just use `agent-browser --cdp 9222`.\n2. **Headed mode with profile**: Use `agent-browser --headed --profile <path>` to open a visible Chrome window.\n3. **State file**: After signing in, save with `agent-browser state save ./auth.json` and reload later with `agent-browser --state ./auth.json`. Note: state files can expire.\n\n### API testing\n- Get a real API key from the UI first (Settings → API Keys) — screenshot the process. **Do not test with fake or dummy API keys**; auth errors mask whether the actual feature works.\n- Configure the CLI/client with the real key, then make real API calls and verify the responses show the expected data.\n- Check both success and error cases.\n\n### Eval testing\n- If the right approach is an eval test, check `__tests__/eval/` for existing tests that cover similar ground\n- Follow the eval test template in `.claude/skills/testing/eval.md`\n- Use `describeEvalMatrix` for cross-model comparison when relevant\n- Use `judgeMultiple` with appropriate `CRITERIA` for subjective outputs\n- Run with `pnpm test-ai eval/<test-name>`\n\n### Hybrid approaches\nOften the best test combines approaches. For example:\n- Use `gws` to create a Google Drive folder with a test PDF\n- Use the browser to configure the feature to use that folder\n- Trigger the feature (send an email, start a chat, etc.)\n- Verify the result in both the UI (screenshot) and via API/database\n\n## Step 4: Report results\n\n**An error means the test failed.** Do not report success if any step produced an error, even if the error seems like a configuration issue. Either fix the configuration and retry, or report the failure clearly.\n\nGive a clear pass/fail summary:\n- What was tested\n- What worked\n- What failed — with screenshots and the actual error\n- What you did to try to fix it\n\nAlways include screenshots — even for passing tests. The user wants to see what the UI looks like.\n\n## Step 5: Persist (if appropriate)\n\nAfter testing, ask the user if this should become a reusable test. Choose the\nsmallest automated boundary that exercises the behavior:\n\n1. **Emulated Playwright test** — for deterministic browser behavior that can\n   run without third-party credentials. Add it under\n   `apps/web/__tests__/playwright/emulated/<area>/` and follow\n   `apps/web/__tests__/playwright/README.md` and the existing fixture patterns.\n\n2. **Real-provider E2E flow** — for Gmail or Outlook delivery, webhooks,\n   provider labels, drafts, or other production-path behavior. Add it under\n   `apps/web/__tests__/e2e/flows/` without replacing provider operations with\n   emulator or database shortcuts.\n\n3. **Eval test** — if the test is about AI output quality, write a proper eval\n   test in `apps/web/__tests__/eval/` that can be run with `pnpm test-ai`.\n\nDon't persist trivial one-off checks (like \"does this page load\"). Persist tests that verify important behavior someone might break later.\n\n## Tool reference\n\n### gws CLI (Google Workspace)\n```bash\n# Create a Drive folder\ngws drive files create --json '{\"name\": \"Test Folder\", \"mimeType\": \"application/vnd.google-apps.folder\"}'\n\n# Upload a file to a folder\ngws drive files create --json '{\"name\": \"test.pdf\", \"parents\": [\"FOLDER_ID\"]}' --upload ./test.pdf\n\n# List Drive files\ngws drive files list --params '{\"q\": \"name contains '\\''test'\\''\", \"pageSize\": 10}'\n\n# Send a Gmail message\ngws gmail users messages send --params '{\"userId\": \"me\"}' --json '{\"raw\": \"BASE64_ENCODED_MESSAGE\"}'\n\n# Create a calendar event\ngws calendar events insert --params '{\"calendarId\": \"primary\"}' --json '{\"summary\": \"Test Event\", \"start\": {\"dateTime\": \"...\"}, \"end\": {\"dateTime\": \"...\"}}'\n```\n\n### Eval test utilities\n- `describeEvalMatrix(name, fn)` — run across models\n- `createEvalReporter()` — track pass/fail\n- `judgeMultiple({ input, output, criteria })` — LLM-as-judge\n- `CRITERIA.*` — ACCURACY, COMPLETENESS, TONE, CONCISENESS, NO_HALLUCINATION, CORRECT_FORMAT\n\n### Existing QA infrastructure\n- Emulated browser tests: `apps/web/__tests__/playwright/emulated/`\n- Real-provider E2E tests: `apps/web/__tests__/e2e/flows/`\n- Eval tests: `apps/web/__tests__/eval/`\n\n<!-- File: .claude/skills/testing/e2e.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Testing Skill\n\nPath: `.claude/skills/testing/e2e.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/e2e.md)\n\n<!-- File: .claude/skills/testing/eval.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Testing Skill\n\nPath: `.claude/skills/testing/eval.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/elie222/inbox-zero/HEAD/.claude/skills/testing/eval.md)\n\n<!-- ... +58 more modular skills available via /api/skills/elie222/inbox-zero?path={path} -->\n</yakaai_skills>"}