commit
Create git commits with user approval and no Claude attribution
Check for TanStack Query pattern violations (query keys, optimistic updates, cache seeding)
$ npx -y skills add dcouple/Pane --agent claude-codeHow it fires
How this command gets triggered: by you, by Claude, or both.
/tanstack-queryContext preview
What this command does when you run it.
Check for TanStack Query pattern violations (query keys, optimistic updates, cache seeding)
allowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git show:*), Bash(git rev-parse:*), Bash(git branch:*), Read, Grep, Glob, TodoWrite description: Check for TanStack Query pattern violations (query keys, optimistic updates, cache seeding)
You are reviewing code changes for violations of **TanStack Query patterns** established in this codebase.
**Canonical reference:** `tmp/research/tanstack-query-guidelines.md` — read this first for full context.
The global `QueryClient` defaults handle freshness. Do NOT add per-query overrides.
**Global defaults (in `providers/QueryProvider.tsx`):**
**Rules:**
Every domain gets its own `<domain>Keys.ts` factory with hierarchical, self-referential keys. Never use raw string arrays. Never add domain keys to the flat `qk` object.
**Gold standard exemplars:**
**Required structure:**
export const domainKeys = {
all: ['domain'] as const,
lists: (workspaceId, params?) => [...domainKeys.all, 'list', workspaceId ?? null, normalizeParams(params)] as const,
detail: (id) => [...domainKeys.all, 'detail', id ?? null] as const,
};**Key properties:**
TanStack Query's `invalidateQueries({ queryKey })` uses **prefix matching**. Calling a factory with no params still produces a full key with trailing defaults, which is **narrower** than the base prefix.
**The trap:**
// BAD: Factory call includes default params, misses other param variants
queryClient.invalidateQueries({ queryKey: conversationKeys.lists(workspaceId) });
// Produces ['conversations', 'list', workspaceId, {}] — misses { includeMessages: true }
// GOOD: Use the predicate helper
invalidateWorkspaceConversations(queryClient, workspaceId);**Rule:** Any domain with parameterized list queries must have an invalidation helper (`<domain>Invalidation.ts`) that uses a predicate to match all variants. Use the predicate helper in all mutations, not raw factory calls.
**When to use what:**
| Scenario | Approach | |----------|----------| | All list variants for a workspace | Predicate helper | | Specific detail query | Exact key: `domainKeys.detail(id)` | | Everything in a domain | Base prefix: `domainKeys.all` | | Simple key with no params | Factory call is fine | | All variants of a parameterized parent | Prefix only, no trailing params: `['workspaces']` |
All optimistic state changes happen inside `useMutation`'s `onMutate` with snapshot + rollback. Never mutate cache from component handlers.
**Exemplar:** `apps/webapp/src/hooks/todos/useTodo.ts` (`useUpdateTodoTitle`)
**Required 6-step pattern:** 1. `cancelQueries` — prevent race conditions 2. Snapshot current state 3. Optimistically update cache 4. Return context for rollback 5. `onError` — restore from snapshot 6. `onSettled` — invalidate to ensure server truth
**When NOT to use optimistic updates:**
**`setQueryData` in `onSuccess` is acceptable** for caching server responses to detail queries (this is NOT an optimistic update).
List-to-detail navigation uses `initialData` to pull from list cache. Eliminates loading spinners.
**Exemplars:**
**Required pattern:**
WebSocket handlers can update cache directly via `setQueryData` — this is server-sourced data, NOT an optimistic update. Always pair with debounced invalidation.
**Rule:** On WebSocket reconnect, invalidate all workspace caches using predicate-based helpers (not specific key variants).
The flat `qk` object is for simple, non-parameterized keys. Anything with parameterized lists, multiple query shapes, or invalidation complexity gets a domain factory.
**Move a key from `qk` to a domain factory when:** 1. It has 3+ query key usages 2. Lists have filter/sort/pagination params 3. You need predicate-based invalidation to match all variants 4. There's a list → detail navigation pattern (cache seeding)
The `@tanstack/query/exhaustive-deps` rule requires all `queryFn` variabl
Repo: dcouple/Pane
Create git commits with user approval and no Claude attribution
You are tasked with creating detailed implementation plans through an interactive, iterative process. You should be skeptical, thorough, and work…
Generate comprehensive PR descriptions following repository templates
You are tasked with implementing an approved technical plan from `thoughts/shared/plans/`. These plans contain phases with specific changes and success…
Iterate on existing implementation plans with thorough research and updates
You are tasked with conducting comprehensive research across the codebase to answer user questions. You will spawn one or more parallel sub-agents to perform…