Token导航 LogoToken导航

Agent Skill · 研究检索

tanstack-db(坦斯塔克数据库)

tanstack-db 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

tanstack-db 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 69,087。

总安装 220周安装 9GitHub Stars 2下载 71核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:tanstack-db(坦斯塔克数据库)
来源仓库:https://github.com/olegakbarov/ispo-code
仓库路径:skills/tanstack-db
安装命令:
npx skills add https://github.com/olegakbarov/ispo-code --skill tanstack-db
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/olegakbarov/ispo-code --skill tanstack-db

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

tanstack-db 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。它可辅助数据库相关信息的聚合与初步筛选,提升 Agent 在技术调研阶段的效率。

通过 npx skills add 命令从指定仓库安装,需结合原始 README 核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

来源仓库内路径:skills/tanstack-db

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/olegakbarov/ispo-code --skill tanstack-db;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

tanstack-db 怎么安装?

在终端执行 npx skills add https://github.com/olegakbarov/ispo-code --skill tanstack-db。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

tanstack-db 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

tanstack-db 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

tanstack-db 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

tanstack-db 用的人多吗?

公开数据是累计安装 220 次,近一周安装 9 次,下载 71 次,GitHub 2 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

tanstack-db 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
tanstack-db

坦斯塔克数据库 · 本页

2202需要联网未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

TanStack DB Skill

Expert guidance for TanStack DB - the reactive client store for building local-first apps with sub-millisecond queries, optimistic mutations, and real-time sync.

Note: TanStack DB is currently in BETA.

Quick Reference

Core Concepts

ConceptPurpose
CollectionTyped set of objects (like a DB table)
Live QueryReactive query that updates incrementally
Optimistic MutationInstant local write, synced in background
Sync EngineReal-time data sync (Electric, RxDB, PowerSync)

Project Structure

src/
├── collections/
│   ├── todos.ts         # Todo collection definition
│   ├── users.ts         # User collection
│   └── index.ts         # Export all collections
├── queries/
│   └── hooks.ts         # Custom live query hooks
└── lib/
    └── db.ts            # DB setup & QueryClient

Installation

# Core + React
npm install @tanstack/react-db @tanstack/db

# With TanStack Query (REST APIs)
npm install @tanstack/query-db-collection @tanstack/react-query

# With ElectricSQL (Postgres sync)
npm install @tanstack/electric-db-collection

# With RxDB (offline-first)
npm install @tanstack/rxdb-db-collection rxdb

Collections

Query Collection (REST API)

// src/collections/todos.ts
import { createCollection } from "@tanstack/react-db"
import { queryCollectionOptions } from "@tanstack/query-db-collection"
import { queryClient } from "@/lib/db"

export interface Todo {
  id: string
  text: string
  completed: boolean
  createdAt: string
}

export const todosCollection = createCollection(
  queryCollectionOptions({
    queryKey: ["todos"],
    queryFn: async () => {
      const res = await fetch("/api/todos")
      return res.json() as Promise<Todo[]>
    },
    queryClient,
    getKey: (item) => item.id,

    // Persistence handlers
    onInsert: async ({ transaction }) => {
      const items = transaction.mutations.map((m) => m.modified)
      await fetch("/api/todos", {
        method: "POST",
        body: JSON.stringify(items),
      })
    },

    onUpdate: async ({ transaction }) => {
      await Promise.all(
        transaction.mutations.map((m) =>
          fetch(`/api/todos/${m.key}`, {
            method: "PATCH",
            body: JSON.stringify(m.changes),
          })
        )
      )
    },

    onDelete: async ({ transaction }) => {
      await Promise.all(
        transaction.mutations.map((m) =>
          fetch(`/api/todos/${m.key}`, { method: "DELETE" })
        )
      )
    },
  })
)

Electric Collection (Postgres Sync)

// src/collections/todos.ts
import { createCollection } from "@tanstack/react-db"
import { electricCollectionOptions } from "@tanstack/electric-db-collection"

export const todosCollection = createCollection(
  electricCollectionOptions({
    id: "todos",
    shapeOptions: {
      url: "/api/electric/todos", // Proxy to Electric
    },
    getKey: (item) => item.id,

    // Use transaction ID for sync confirmation
    onInsert: async ({ transaction }) => {
      const item = transaction.mutations[0].modified
      const res = await fetch("/api/todos", {
        method: "POST",
        body: JSON.stringify(item),
      })
      const { txid } = await res.json()
      return { txid } // Electric waits for this txid
    },

    onUpdate: async ({ transaction }) => {
      const { key, changes } = transaction.mutations[0]
      const res = await fetch(`/api/todos/${key}`, {
        method: "PATCH",
        body: JSON.stringify(changes),
      })
      const { txid } = await res.json()
      return { txid }
    },

    onDelete: async ({ transaction }) => {
      const { key } = transaction.mutations[0]
      const res = await fetch(`/api/todos/${key}`, { method: "DELETE" })
      const { txid } = await res.json()
      return { txid }
    },
  })
)

Sync Modes

// Eager (default): Load all upfront - best for <10k rows
electricCollectionOptions({
  sync: { mode: "eager" },
  // ...
})

// On-demand: Load only what queries request - best for >50k rows
electricCollectionOptions({
  sync: { mode: "on-demand" },
  // ...
})

// Progressive: Instant query results + background full sync
electricCollectionOptions({
  sync: { mode: "progressive" },
  // ...
})

Live Queries

Basic Query

import { useLiveQuery } from "@tanstack/react-db"
import { todosCollection } from "@/collections/todos"

function TodoList() {
  const { data: todos, isLoading } = useLiveQuery((q) =>
    q.from({ todo: todosCollection })
  )

  if (isLoading) return <div>Loading...</div>

  return (
    <ul>
      {todos?.map((todo) => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  )
}

Filtering with Where

import { eq, gt, and, or, like, inArray } from "@tanstack/react-db"

// Simple equality
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .where(({ todo }) => eq(todo.completed, false))
)

// Multiple conditions
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .where(({ todo }) =>
     and(
       eq(todo.completed, false),
       gt(todo.priority, 5)
     )
   )
)

// OR conditions
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .where(({ todo }) =>
     or(
       eq(todo.status, "urgent"),
       eq(todo.status, "high")
     )
   )
)

// String matching
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .where(({ todo }) => like(todo.text, "%meeting%"))
)

// In array
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .where(({ todo }) => inArray(todo.id, ["1", "2", "3"]))
)

Comparison Operators

OperatorDescription
eq(a, b)Equal
gt(a, b)Greater than
gte(a, b)Greater than or equal
lt(a, b)Less than
lte(a, b)Less than or equal
like(a, pattern)Case-sensitive match
ilike(a, pattern)Case-insensitive match
inArray(a, arr)Value in array
isNull(a)Is null
isUndefined(a)Is undefined

Sorting and Pagination

useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .orderBy(({ todo }) => todo.createdAt, "desc")
   .limit(20)
   .offset(0)
)

Select Projection

// Select specific fields
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .select(({ todo }) => ({
     id: todo.id,
     text: todo.text,
     done: todo.completed,
   }))
)

// Computed fields
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .select(({ todo }) => ({
     id: todo.id,
     displayText: upper(todo.text),
     isOverdue: lt(todo.dueDate, new Date().toISOString()),
   }))
)

Joins

import { usersCollection } from "@/collections/users"

// Inner join
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .join(
     { user: usersCollection },
     ({ todo, user }) => eq(todo.userId, user.id),
     "inner"
   )
   .select(({ todo, user }) => ({
     id: todo.id,
     text: todo.text,
     assignee: user.name,
   }))
)

// Left join (default)
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .leftJoin(
     { user: usersCollection },
     ({ todo, user }) => eq(todo.userId, user.id)
   )
)

Aggregations

// Group by with aggregates
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .groupBy(({ todo }) => todo.status)
   .select(({ todo }) => ({
     status: todo.status,
     count: count(todo.id),
     avgPriority: avg(todo.priority),
   }))
)

// With having clause
useLiveQuery((q) =>
  q.from({ order: ordersCollection })
   .groupBy(({ order }) => order.customerId)
   .select(({ order }) => ({
     customerId: order.customerId,
     totalSpent: sum(order.amount),
   }))
   .having(({ $selected }) => gt($selected.totalSpent, 1000))
)

Find Single Item

// Returns T | undefined
useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .where(({ todo }) => eq(todo.id, todoId))
   .findOne()
)

Reactive Dependencies

// Re-run query when deps change
const [filter, setFilter] = useState("all")

useLiveQuery(
  (q) =>
    q.from({ todo: todosCollection })
     .where(({ todo }) =>
       filter === "all" ? true : eq(todo.status, filter)
     ),
  [filter] // Dependency array
)

Mutations

Basic Operations

const { collection } = useLiveQuery((q) =>
  q.from({ todo: todosCollection })
)

// Insert
collection.insert({
  id: crypto.randomUUID(),
  text: "New todo",
  completed: false,
  createdAt: new Date().toISOString(),
})

// Insert multiple
collection.insert([item1, item2, item3])

// Update (immutable draft pattern)
collection.update(todoId, (draft) => {
  draft.completed = true
  draft.completedAt = new Date().toISOString()
})

// Update multiple
collection.update([id1, id2], (drafts) => {
  drafts.forEach((d) => (d.completed = true))
})

// Delete
collection.delete(todoId)

// Delete multiple
collection.delete([id1, id2, id3])

Non-Optimistic Mutations

// Skip optimistic update, wait for server
collection.insert(item, { optimistic: false })
collection.update(id, updater, { optimistic: false })
collection.delete(id, { optimistic: false })

Custom Optimistic Actions

import { createOptimisticAction } from "@tanstack/react-db"

// Multi-collection or complex mutations
const likePost = createOptimisticAction<string>({
  onMutate: (postId) => {
    postsCollection.update(postId, (draft) => {
      draft.likeCount += 1
      draft.likedByMe = true
    })
  },
  mutationFn: async (postId) => {
    await fetch(`/api/posts/${postId}/like`, { method: "POST" })
    // Optionally refetch
    await postsCollection.utils.refetch()
  },
})

// Usage
likePost.mutate(postId)

Manual Transactions

import { createTransaction } from "@tanstack/react-db"

const tx = createTransaction({
  autoCommit: false,
  mutationFn: async ({ transaction }) => {
    // Batch all mutations in single request
    await fetch("/api/batch", {
      method: "POST",
      body: JSON.stringify(transaction.mutations),
    })
  },
})

// Queue mutations
tx.mutate(() => {
  todosCollection.insert(newTodo)
  todosCollection.update(existingId, (d) => (d.status = "active"))
  todosCollection.delete(oldId)
})

// Commit or rollback
await tx.commit()
// or
tx.rollback()

Paced Mutations (Debounce/Throttle)

import { usePacedMutations, debounceStrategy } from "@tanstack/react-db"

// Debounce rapid updates (e.g., text input)
const { mutate } = usePacedMutations({
  onMutate: (value: string) => {
    todosCollection.update(todoId, (d) => (d.text = value))
  },
  mutationFn: async ({ transaction }) => {
    const changes = transaction.mutations[0].changes
    await fetch(`/api/todos/${todoId}`, {
      method: "PATCH",
      body: JSON.stringify(changes),
    })
  },
  strategy: debounceStrategy({ wait: 500 }),
})

// Usage in input
<input onChange={(e) => mutate(e.target.value)} />

Provider Setup

// src/main.tsx
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { DBProvider } from "@tanstack/react-db"

const queryClient = new QueryClient()

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <DBProvider>
        <Router />
      </DBProvider>
    </QueryClientProvider>
  )
}

Electric Backend Setup

Server-Side Transaction ID

// api/todos/route.ts (example with Drizzle)
import { db } from "@/db"
import { todos } from "@/db/schema"
import { sql } from "drizzle-orm"

export async function POST(req: Request) {
  const data = await req.json()

  const result = await db.transaction(async (tx) => {
    // Insert the todo
    const [todo] = await tx.insert(todos).values(data).returning()

    // Get transaction ID in SAME transaction
    const [{ txid }] = await tx.execute(
      sql`SELECT pg_current_xact_id()::text as txid`
    )

    return { todo, txid: parseInt(txid, 10) }
  })

  return Response.json(result)
}

Electric Proxy Route

// api/electric/[...path]/route.ts
export async function GET(req: Request) {
  const url = new URL(req.url)
  const electricUrl = `${process.env.ELECTRIC_URL}${url.pathname}${url.search}`

  return fetch(electricUrl, {
    headers: { Authorization: `Bearer ${process.env.ELECTRIC_TOKEN}` },
  })
}

Utility Methods

// Refetch collection data
await collection.utils.refetch()

// Direct writes (bypass optimistic state)
collection.utils.writeInsert(item)
collection.utils.writeUpdate(item)
collection.utils.writeDelete(id)
collection.utils.writeUpsert(item)

// Batch direct writes
collection.utils.writeBatch(() => {
  collection.utils.writeInsert(item1)
  collection.utils.writeDelete(id2)
})

// Wait for Electric sync (with txid)
await collection.utils.awaitTxId(txid, 30000)

// Wait for custom match
await collection.utils.awaitMatch(
  (msg) => msg.value.id === expectedId,
  5000
)

Gotchas and Tips

  1. Queries run client-side: TanStack DB is NOT an ORM - queries run locally against collections, not against a database
  2. Sub-millisecond updates: Uses differential dataflow - only recalculates affected parts of queries
  3. Transaction IDs matter: With Electric, always get pg_current_xact_id() in the SAME transaction as mutations
  4. Sync modes: Use "eager" for small datasets, "on-demand" for large, "progressive" for collaborative apps
  5. Optimistic by default: All mutations apply instantly; use {optimistic: false} for server-validated operations
  6. Fine-grained reactivity: Only components using changed data re-render
  7. Mutation merging: Rapid updates merge automatically (insert+update→insert, update+update→merged)
  8. Collection = complete state: Empty array from queryFn clears the collection

Common Patterns

Loading States

function TodoList() {
  const { data, isLoading, isPending } = useLiveQuery((q) =>
    q.from({ todo: todosCollection })
  )

  if (isLoading) return <Skeleton />
  if (!data?.length) return <EmptyState />

  return <List items={data} />
}

Mutation with Feedback

function TodoItem({ todo }: { todo: Todo }) {
  const { collection } = useLiveQuery((q) =>
    q.from({ todo: todosCollection })
  )

  const toggle = async () => {
    const tx = collection.update(todo.id, (d) => {
      d.completed = !d.completed
    })

    try {
      await tx.isPersisted.promise
      toast.success("Saved!")
    } catch (err) {
      toast.error("Failed to save")
      // Optimistic update already rolled back
    }
  }

  return <Checkbox checked={todo.completed} onChange={toggle} />
}

Derived/Computed Collections

// Create a "view" with live query
const completedTodos = useLiveQuery((q) =>
  q.from({ todo: todosCollection })
   .where(({ todo }) => eq(todo.completed, true))
   .orderBy(({ todo }) => todo.completedAt, "desc")
)

平台分布

Codex

34.59%
按下载量换算25

Claude

29.91%
按下载量换算21

Cursor

19.09%
按下载量换算14

Gemini CLI

9.52%
按下载量换算7

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills