CommunityRedacción y edicióngithub.com

Texarkanine/stockroom

Un almacén local, fiel y consultable de tu historial de codificación agéntica.

¿Qué es stockroom?

Este skill proporciona acceso de solo lectura a un almacén DuckDB local que captura tu historial completo de sesiones de Cursor y Claude Code. Es ideal para realizar búsquedas estructuradas y exactas: consultas SQL para contar sesiones, listar herramientas usadas, sumar tokens por sesión, filtrar por campos conocidos (ID, fecha, modelo) y hacer uniones entre tablas. El almacén está construido para ser inmutable por diseño, por lo que no puedes dañar los datos. Se invoca mediante el comando `stockroom query` con opciones para formatear la salida (TSV, JSON, tabla) y controlar el nivel de detalle de los campos largos (desde resumen compacto hasta texto completo). Está pensado para preguntas con una forma conocida; para búsquedas semánticas usa el skill `sr-semantic`.

Compatible con✓Claude Code~Codex CLI✓Cursor✓Antigravity
npx skills add Texarkanine/stockroom

Installed? Explore more Redacción y edición skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

sr-query

sr-query ejecuta SQL de solo lectura contra el almacén stockroom — la base de datos DuckDB de un solo archivo que contiene tu historial capturado de Cursor + Claude Code. La superficie es de solo lectura por construcción: DuckDB rechaza cualquier escritura que se intente a través de ella, por lo que no puedes corromper nada al consultar.

Cuándo usar sr-query

Recurre a sr-query cuando la pregunta tenga una forma conocida y la respuesta sea una búsqueda exacta o estructurada sobre campos que puedas nombrar:

  • Una fila específica por id (WHERE message_id = '…', WHERE session_id = '…').
  • Filtros, conteos y resúmenes (COUNT(*), GROUP BY harness, WHERE harness = 'claude', sumas de tokens, rangos de fechas).
  • Resúmenes de tokens por sesión mediante la VISTA session_token_usage (prefiere esto sobre un SUM hecho a mano en messages).
  • Uniones entre sessions / messages / tool_calls.
  • "Cuántos", "qué sesiones", "lista las llamadas a herramientas", "qué modelos" — cualquier cosa que puedas expresar como SQL sobre columnas con nombre.

No uses sr-query para recuperación basada en significado ("encuentra conversaciones sobre pruebas inestables"). SQL ILIKE es una coincidencia literal de subcadena, no búsqueda semántica — para significado, usa el skill sr-semantic. Cuando no estés seguro de cuál es el correcto, ese juicio le corresponde al skill sr-search.

Cómo invocar el motor

stockroom query "SELECT DISTINCT harness FROM sessions ORDER BY harness"

También puedes canalizar SQL desde stdin con -:

echo "SELECT count(*) FROM messages" | stockroom query -

Si command -v stockroom falla, la máquina no está configurada: dile al usuario que ejecute el skill sr-initialize, y no intentes ninguna otra invocación.

Disciplina de salida: --format y --detail

Los valores predeterminados ya son seguros para un agente — una llamada simple produce una salida acotada y analizable — así que recurre a las banderas solo cuando la situación lo requiera.

--format — forma de la salida, por defecto tsv

ValorFormaÚsalo cuando
tsv (predeterminado)Fila de encabezado + filas separadas por tabuladores, sin contador de filasPredeterminado. Amigable para flujo y para pipelines unix (cut, awk, wc -l).
jsonUn único objeto {"columns": [...], "rows": [...]}Un usuario pide salida estructurada/máquina, o quieres pasársela a jq.
tableASCII alineado por columnas con un pie de (N filas)Un usuario pide algo legible para humanos / un comando copiable para mirar.

Empieza con el predeterminado tsv. Ofrece --format table o --format json cuando el usuario lo pida para salida legible o estructurada — "estas otras formas existen si las quieres".

--detail — ancho por campo, por defecto snippet

Los campos de cadena anchos (notablemente messages.text y tool_calls.tool_input) se truncan en tiempo de lectura para que una columna grande no inunde tu contexto. El truncamiento es solo de visualización — el texto completo siempre se puede recuperar.

ValorPresupuesto por campoÚsalo cuando
compact~40 caracteresEscaneando muchas filas candidatas de forma barata antes de elegir una.
snippet (predeterminado)~120 caracteresPredeterminado. Suficiente para reconocer una fila sin volcarla.
fullsin límite, una sola líneaNecesitas toda la longitud del campo, y el colapso en una línea está bien (las tablas/TSV se mantienen seguros).
rawsin límite, espacios en blanco exactosNecesitas el texto tal como está almacenado — saltos de línea y espacios internos intactos. Prefiérelo con --format json.

Un campo que excede el presupuesto se elide con un marcador que indica cuántos caracteres se ocultaron, p. ej. …(+2284). Ese marcador es tu señal de que existe más: si realmente lo necesitas, vuelve a recuperar solo ese campo para la fila específica con --detail full (longitud) o --format json --detail raw (espacios en blanco exactos) — consulta las salvaguardas.

Salvaguardas

Estos son los modos de fallo que este skill existe para prevenir:

  • No satures tu contexto. Nunca hagas SELECT * (o una columna text ancha) con --detail full/raw en muchas filas. En su lugar: escanea de forma estrecha con --detail compact/snippet y una lista de columnas explícita y un LIMIT, identifica la fila que quieres, luego vuelve a recuperar solo el campo ancho de esa fila con un WHERE en su id. Un solo SELECT text FROM messages WHERE message_id = '…' es barato; SELECT * FROM messages --detail full es una bomba de contexto. Cuando necesites exactamente los espacios en blanco (tablas markdown, bloques de código), usa --format json --detail raw.
  • Es de solo lectura — nunca intentes escrituras. INSERT / UPDATE / DELETE / CREATE fallan todas (query failed: …). No reintentes una escritura con otra redacción; la superficie solo interroga.
  • tool_input es JSON heterogéneo. Sus claves varían por herramienta (Shell tiene command, Read tiene path, …), por lo que un tool_input->>'key' ingenuo puede lanzar un error de conversión. Extrae de forma segura filtrando tool_name en una subconsulta/CTE primero y usando la función explícita:
stockroom query "SELECT json_extract_string(tool_input, '\$.command') AS cmd
  FROM (SELECT tool_input FROM tool_calls WHERE tool_name = 'Shell') LIMIT 5"

Manejar errores sin aleteo

Cada fallo es un mensaje limpio en stderr + código de salida — léelo y toma la acción correspondiente, no hagas un bucle:

MensajeSalidaQué significa / siguiente acción
error: empty query (…)2No se pasó SQL. Proporciona una sentencia.
error: no warehouse found at … — run \stockroom ingest` first`1El almacén no se ha construido. Dile al usuario que ejecute stockroom ingest (o sr-initialize si la máquina nunca se configuró); no reintentes la consulta.
query failed: …1SQL inválido, o se rechazó una escritura. Corrige la sentencia (lee el mensaje de DuckDB) — no vuelvas a ejecutar el mismo SQL.

Qué hay en el almacén

Descubre el esquema en vivo primero — esto se mantiene correcto a medida que el esquema evoluciona:

stockroom query "SELECT table_name, column_name, data_type
  FROM information_schema.columns ORDER BY table_name, ordinal_position"

Referencia rápida de las columnas importantes a partir de las migraciones 0001–0008 (confírmalo con la consulta de introspección anterior):

  • sessions — una fila por conversación. harness ('cursor'|'claude'), session_id, project_id (slug del directorio del proyecto textual — la clave de agrupación; para los chats CLI de Cursor esto es el directorio hash de los chats), cwd (ruta real, puede ser NULL), workspace_key (resumen de ruta entre herramientas, puede ser NULL), entrypoint (procedencia superficial desde la herramienta cuando se conoce; puede ser NULL — usa SELECT DISTINCT entrypoint en lugar de adivinar literales), models (VARCHAR[], solo Cursor), title, git_branch, is_subagent, parent_session_id, started_at, ended_at, source_mtime (mtime de la transcripción fuente en la última ingesta), y cuatro BIGINT de token por sesión anulables (input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens — se llenan solo cuando una herramienta reporta uso a nivel de conversación; Claude/Cursor los dejan como NULL). PK (harness, session_id).
  • messages — una fila por turno. message_id = '{session_id}#{ordinal}' (uniforme entre herramientas), parent_id, ordinal, role ('user'|'assistant'), text (completo; el pensamiento no se captura), model (por mensaje, solo Claude), ts, first_seen_at (cuando stockroom observó el mensaje por primera vez), y cuatro BIGINT de token: input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens (uso de mensaje de Claude; Cursor NULL). PK (harness, session_id, message_id).
  • session_token_usage — VISTA sobre sesiones + sumas de tokens de mensajes. Prefiere esta para resúmenes de conversación. Columnas: *_from_messages (SUM), *_native (columnas de sesión), *_total (COALESCE(native, from_messages)), token_grain ('session'|'message'|'none'). Los totales son resúmenes del almacén de campos reportados, no facturas de proveedores. No hagas también SUM de tokens de mensajes además de *_total.
  • tool_calls — solo entradas de herramientas (nunca salidas). message_id (el turno que lo emitió), ordinal, tool_name, tool_input (JSON heterogéneo, almacenado completo — consulta la salvaguarda). PK (harness, session_id, message_id, ordinal).
  • embeddings — vectores por fragmento para búsqueda semántica (owner_table, owner_id, chunk_index, embed_model, vector FLOAT[384]). Rara vez consultas esto directamente — usa el skill sr-semantic.
  • _sync_state — contabilidad de marcas de agua de ingesta; no interesante para consultar.

Una regla de identidad que vale la pena conocer antes de escribir una unión: únete siempre mediante el message_id / (harness, session_id) uniforme, nunca en las columnas de procedencia source_*. Un valor que solo existe en un nivel por herramienta es honestamente NULL para el otro (p. ej. messages.model es solo de Claude; sessions.models es solo de Cursor; la misma honestidad de doble nivel se aplica a los tokens).

Ejemplos prácticos

Todos verificados contra un almacén real.

# Qué herramientas están presentes? (tsv predeterminado)
stockroom query "SELECT DISTINCT harness FROM sessions ORDER BY harness"

# Conteos de sesiones por herramienta, legible para un usuario:
stockroom query --format table "SELECT harness, count(*) AS n FROM sessions GROUP BY harness ORDER BY n DESC"

# Herramientas más ocupadas:
stockroom query "SELECT tool_name, count(*) AS calls FROM tool_calls GROUP BY tool_name ORDER BY calls DESC LIMIT 5"

# Escanea mensajes candidatos de forma barata, luego recupera el que quieras completo:
stockroom query --detail compact "SELECT message_id, text FROM messages WHERE text ILIKE '%flaky test%' LIMIT 10"
stockroom query --format json --detail raw \
  "SELECT text FROM messages WHERE message_id = '<id-from-the-scan>'"

# Salida estructurada para que un usuario/herramienta consuma:
stockroom query --format json "SELECT harness, session_id, title FROM sessions WHERE title IS NOT NULL LIMIT 5"

# Resúmenes de tokens por sesión (VISTA session_token_usage):
stockroom query --format table \
  "SELECT harness, session_id, input_tokens_total, output_tokens_total, token_grain
   FROM session_token_usage
   ORDER BY input_tokens_total DESC NULLS LAST
   LIMIT 10"

Más variantes (herramientas sin límite con ventana de actividad, resúmenes de tokens por día/herramienta, SQL de uso de habilidades por herramienta): consulta el Cookbook.

Cookbook

SQL inicial complicado: references/cookbook/. Abre el índice, luego solo la receta que necesites.

Transmitir a un humano

Tú eres el operador de la herramienta, no su pantalla. Ejecuta el SQL, lee el resultado y responde al usuario en lenguaje natural. No pegues tsv sin procesar a un humano a menos que haya pedido verlo. Cuando sí quiera la salida sin procesar — o un comando para ejecutar él mismo — entrégale una variante con --format table (para leer) o --format json (para procesar).

Entender el sistema

Para entender por qué estos contratos tienen este aspecto — el empaquetado, el contrato torch, solo-lectura-por-construcción, la doctrina de truncamiento, identidad/procedencia — lee el modelo de sistema compartido: ../sr-search/references/system-model.md.

Skills relacionados