CommunityEscrita e Ediçãogithub.com

Texarkanine/stockroom

Um depósito local, fiel e pesquisável do seu histórico de codificação agentiva.

O que é stockroom?

O Texarkanine/stockroom é uma skill que fornece consultas SQL somente leitura em um banco de dados DuckDB local, capturando o histórico completo de sessões do Cursor e Claude Code. Ela permite que o agente execute buscas estruturadas por campos como `message_id`, `harness`, `model`, ou faça agregações como contagens e somas de tokens via a VIEW `session_token_usage`. A skill é segura por construção (DuckDB rejeita escritas) e evita sobrecarga de contexto com truncamento inteligente de campos longos. Suporta saída em formatos TSV (padrão), JSON e tabela ASCII, sendo ideal para perguntas com formato conhecido, enquanto delega buscas semânticas para as skills `sr-semantic` e `sr-search`.

Funciona com✓Claude Code~Codex CLI✓Cursor✓Antigravity
npx skills add Texarkanine/stockroom

Installed? Explore more Escrita e Edição skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

sr-query

sr-query executa SQL somente leitura no warehouse do stockroom — o banco de dados DuckDB de arquivo único do seu histórico capturado do Cursor + Claude Code. A superfície é somente leitura por construção: DuckDB rejeita qualquer tentativa de escrita, então você não pode corromper nada ao consultar.

Quando usar o sr-query

Recorra ao sr-query quando a pergunta tiver um formato conhecido e a resposta for uma consulta exata ou estruturada sobre campos que você pode nomear:

  • Uma linha específica por id (WHERE message_id = '…', WHERE session_id = '…').
  • Filtros, contagens e agregações (COUNT(*), GROUP BY harness, WHERE harness = 'claude', somas de tokens, intervalos de datas).
  • Agregações de tokens por sessão via VIEW session_token_usage (prefira isto a SUM manual em messages).
  • Joins entre sessions / messages / tool_calls.
  • "Quantas", "quais sessões", "liste as chamadas de ferramenta", "quais modelos" — tudo que você possa expressar como SQL sobre colunas nomeadas.

Não use sr-query para recuperação baseada em significado ("encontre conversas sobre testes instáveis"). SQL ILIKE é uma correspondência literal de substring, não busca semântica — para significado, use a skill sr-semantic. Quando você não tiver certeza de qual é a correta, esse julgamento pertence à skill sr-search.

Como invocar o motor

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

Você também pode passar SQL pela entrada padrão com -:

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

Se command -v stockroom falhar, a máquina não está configurada: diga ao usuário para executar a skill sr-initialize, e não tente nenhuma outra invocação.

Disciplina de saída: --format e --detail

Os padrões já são seguros para um agente — uma chamada simples dá saída limitada e analisável — então recorra às flags apenas quando a situação exigir.

--format — formato da saída, padrão tsv

ValorFormatoUse quando
tsv (padrão)Linha de cabeçalho + linhas separadas por tabulação, sem contagem finalPadrão. Amigável para fluxo e para pipes Unix (cut, awk, wc -l).
jsonUm único objeto {"columns": [...], "rows": [...]}Um usuário pede saída estruturada/de máquina, ou você quer passar para jq.
tableASCII alinhado por colunas com rodapé (N rows)Um usuário pede algo legível / um comando copiável para olhar.

Use o padrão tsv. Ofereça --format table ou --format json quando o usuário pedir saída legível ou estruturada — "estes outros formatos existem se você quiser."

--detail — largura por campo, padrão snippet

Campos de string longos (notadamente messages.text e tool_calls.tool_input) são truncados no momento da leitura para que uma coluna grande não inunde seu contexto. O truncamento é apenas de exibição — o texto completo sempre pode ser recuperado.

ValorOrçamento por campoUse quando
compact~40 caracteresEscaneando muitas linhas candidatas de forma barata antes de escolher uma.
snippet (padrão)~120 caracteresPadrão. Suficiente para reconhecer uma linha sem despejá-la.
fullilimitado, linha únicaVocê precisa do comprimento total do campo, e a quebra de linha única é aceitável (tabelas/TSV permanecem seguros).
rawilimitado, espaçamento exatoVocê precisa do texto como armazenado — quebras de linha e espaços internos intactos. Prefira com --format json.

Um campo acima do orçamento é omitido com um marcador reportando quantos caracteres foram ocultados, ex.: …(+2284). Esse marcador é seu sinal de que mais existe: se você realmente precisar, busque novamente apenas aquele campo para a linha específica com --detail full (comprimento) ou --format json --detail raw (espaçamento exato) — veja as proteções.

Proteções

Estes são os modos de falha que esta skill existe para prevenir:

  • Não exploda seu contexto. Nunca use SELECT * (ou uma coluna text larga) com --detail full/raw em muitas linhas. Em vez disso: escaneie de forma estreita com --detail compact/snippet com uma lista explícita de colunas e um LIMIT, identifique a linha desejada, então busque novamente apenas o campo largo daquela linha com um WHERE em seu id. Um único SELECT text FROM messages WHERE message_id = '…' é barato; SELECT * FROM messages --detail full é uma bomba de contexto. Quando você precisar de espaçamento exato (tabelas markdown, blocos de código), use --format json --detail raw.
  • É somente leitura — nunca tente escritas. INSERT / UPDATE / DELETE / CREATE tudo falha (query failed: …). Não tente novamente uma escrita com uma formulação diferente; a superfície apenas interroga.
  • tool_input é JSON heterogêneo. Suas chaves variam por ferramenta (Shell tem command, Read tem path, …), então um tool_input->>'key' ingênuo pode gerar um erro de cast. Extraia com segurança filtrando tool_name em uma subconsulta/CTE primeiro e usando a função 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"

Trate erros sem repetição

Cada falha é uma mensagem limpa no stderr + código de saída — leia e tome a ação correspondente, não faça loop:

MensagemSaídaO que significa / próxima ação
error: empty query (…)2Nenhum SQL foi passado. Forneça uma instrução.
error: no warehouse found at … — run \stockroom ingest` first`1O warehouse não foi construído. Diga ao usuário para executar stockroom ingest (ou sr-initialize se a máquina nunca foi configurada); não tente a consulta novamente.
query failed: …1SQL inválido, ou uma escrita foi rejeitada. Corrija a instrução (leia a mensagem do DuckDB) — não execute o mesmo SQL novamente.

O que está no warehouse

Descubra o esquema ativo primeiro — isso permanece correto à medida que o esquema evolui:

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

Referência rápida das colunas principais a partir das migrações 0001–0008 (confirme com a consulta de introspecção acima):

  • sessions — uma linha por conversa. harness ('cursor'|'claude'), session_id, project_id (slug do diretório do projeto — a chave de agrupamento; para chats do Cursor CLI este é o diretório hash dos chats), cwd (caminho real, pode ser NULL), workspace_key (agregação de caminho entre harnesses, pode ser NULL), entrypoint (proveniência da superfície do harness quando conhecido; pode ser NULL — use SELECT DISTINCT entrypoint em vez de adivinhar literais), models (VARCHAR[], apenas Cursor), title, git_branch, is_subagent, parent_session_id, started_at, ended_at, source_mtime (mtime do transcripto fonte na última ingestão), e quatro BIGINTs de token por sessão anuláveis (input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens — preenchidos apenas quando um harness reporta uso no nível da conversa; Claude/Cursor os deixam NULL). PK (harness, session_id).
  • messages — uma linha por turno. message_id = '{session_id}#{ordinal}' (uniforme entre harnesses), parent_id, ordinal, role ('user'|'assistant'), text (todo; pensamento não é capturado), model (por mensagem, apenas Claude), ts, first_seen_at (quando o stockroom observou a mensagem pela primeira vez), e quatro BIGINTs de token: input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens (uso de mensagem do Claude; Cursor NULL). PK (harness, session_id, message_id).
  • session_token_usage — VIEW sobre sessões + somas de tokens de mensagens. Prefira esta para agregações de conversa. Colunas: *_from_messages (SUM), *_native (colunas da sessão), *_total (COALESCE(native, from_messages)), token_grain ('session'|'message'|'none'). Os totais são agregações do warehouse dos campos reportados, não faturas de fornecedores. Não faça também SUM de tokens de mensagem além de *_total.
  • tool_calls — apenas entradas de ferramenta (nunca saídas). message_id (o turno que a emitiu), ordinal, tool_name, tool_input (JSON heterogêneo, armazenado completo — veja a proteção). PK (harness, session_id, message_id, ordinal).
  • embeddings — vetores por chunk para busca semântica (owner_table, owner_id, chunk_index, embed_model, vector FLOAT[384]). Raramente você consulta isto diretamente — use a skill sr-semantic.
  • _sync_state — contabilidade de marcas d'água de ingestão; não é interessante para consultar.

Uma regra de identidade que vale a pena saber antes de escrever um join: sempre junte pelo message_id / (harness, session_id) uniforme, nunca pelas colunas de proveniência source_*. Um valor que existe apenas em um grão por harness é honestamente NULL para o outro (ex.: messages.model é apenas Claude; sessions.models é apenas Cursor; a mesma honestidade de grão duplo se aplica a tokens).

Exemplos práticos

Todos verificados contra um warehouse real.

# Quais harnesses estão presentes? (tsv padrão)
stockroom query "SELECT DISTINCT harness FROM sessions ORDER BY harness"

# Contagens de sessões por harness, legível para um usuário:
stockroom query --format table "SELECT harness, count(*) AS n FROM sessions GROUP BY harness ORDER BY n DESC"

# Ferramentas mais usadas:
stockroom query "SELECT tool_name, count(*) AS calls FROM tool_calls GROUP BY tool_name ORDER BY calls DESC LIMIT 5"

# Escaneie mensagens candidatas de forma barata, depois busque novamente a desejada por 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>'"

# Saída estruturada para um usuário/ferramenta consumir:
stockroom query --format json "SELECT harness, session_id, title FROM sessions WHERE title IS NOT NULL LIMIT 5"

# Agregações de tokens por sessão (VIEW 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"

Mais variantes (ferramentas ilimitadas com janela de atividade, agregações de tokens por dia/harness, SQL de uso de skill por harness): veja o Cookbook.

Cookbook

SQL inicial complicado: references/cookbook/. Abra o índice e depois apenas a receita que você precisa.

Relato a um humano

Você é o operador da ferramenta, não sua tela. Execute o SQL, leia o resultado e responda ao usuário em linguagem natural. Não cole TSV bruto para um humano a menos que ele tenha pedido para vê-lo. Quando ele quiser a saída bruta — ou um comando para executar ele mesmo — forneça uma variante --format table (para ler) ou --format json (para processar).

Entendendo o sistema

Para entender por que esses contratos são como são — o empacotamento, o contrato tocha, somente leitura por construção, a doutrina de truncamento, identidade/proveniência — leia o modelo de sistema compartilhado: ../sr-search/references/system-model.md.

Habilidades Relacionadas