Community라이팅 & 에디팅github.com

sr-query

로컬의 충실하고 검색 가능한 에이전트 코딩 기록 저장소에 대해 읽기 전용 SQL을 실행합니다.

sr-query란 무엇인가요?

`sr-query` 스킬은 Cursor와 Claude Code로 캡처된 에이전트 코딩 세션의 기록을 단일 파일 DuckDB 데이터베이스(Stockroom 웨어하우스)에 저장하고, 이에 대해 읽기 전용 SQL 질의를 실행할 수 있게 해줍니다. DuckDB가 쓰기 작업을 거부하므로 데이터가 손상될 위험이 없으며, 에이전트는 안전하게 데이터를 탐색할 수 있습니다. 특정 행 ID 조회, 세션/메시지/도구 호출 테이블 간 조인, 토큰 사용량 집계 등 정확하고 구조화된 검색에 적합합니다. 의미 기반 검색이 필요한 경우 `sr-semantic` 스킬을, 어떤 스킬을 사용할지 판단이 필요하면 `sr-search` 스킬을 사용하도록 설계되었습니다. 출력 형식은 기본 TSV이며, JSON, 테이블 형식도 지원하고 필드 세부 수준(compact, snippet, full, raw)을 조절하여 컨텍스트 폭발을 방지합니다.

지원 대상✓Claude Code~Codex CLI✓Cursor✓Antigravity
npx skills add Texarkanine/stockroom

Installed? Explore more 라이팅 & 에디팅 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

sr-query은(는) 무엇을 하나요?

sr-query는 stockroom 웨어하우스 — Cursor + Claude Code 기록이 담긴 단일 파일 DuckDB 데이터베이스 — 에 대해 읽기 전용 SQL을 실행합니다. 표면은 설계상 읽기 전용입니다. DuckDB가 이를 통한 모든 쓰기를 거부하므로 질의로 데이터를 손상시킬 수 없습니다.

sr-query를 사용해야 할 때

질문이 알려진 형태를 가지고 있으며, 답변이 이름을 지정할 수 있는 필드에 대한 정확하거나 구조화된 조회일 때 sr-query를 사용하십시오.

  • ID로 특정 행 (WHERE message_id = '…', WHERE session_id = '…')
  • 필터, 개수, 롤업 (COUNT(*), GROUP BY harness, WHERE harness = 'claude', 토큰 합계, 날짜 범위)
  • VIEW session_token_usage를 통한 세션별 토큰 롤업 (messages에 대해 수동 SUM을 사용하는 것보다 선호)
  • sessions / messages / tool_calls 간 조인
  • "몇 개", "어떤 세션", "도구 호출 목록", "어떤 모델" — 열 이름을 지정해 SQL로 표현할 수 있는 모든 것

의미 기반 회상("플래키 테스트에 대한 대화 찾기")에는 sr-query를 사용하지 마십시오. SQL ILIKE는 리터럴 부분 문자열 일치이지, 의미 검색이 아닙니다 — 의미 검색은 sr-semantic 스킬을 사용하십시오. 어떤 것이 적합한지 확실하지 않다면, 그 판단은 sr-search 스킬에 속합니다.

엔진 호출 방법

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

stdin에서 -를 사용하여 SQL을 파이프로 전달할 수도 있습니다:

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

command -v stockroom 명령이 실패하면, 시스템이 아직 설정되지 않은 것입니다: 사용자에게 sr-initialize 스킬을 실행하라고 알리고, 다른 호출을 시도하지 마십시오.

출력 규율: --format 및 --detail

기본값은 이미 에이전트에게 안전합니다 — 기본 호출은 범위가 제한되고 파싱 가능한 출력을 제공합니다 — 따라서 상황이 요구할 때만 플래그를 사용하십시오.

--format — 출력 형태, 기본값 tsv

값형태사용 시기
tsv (기본값)헤더 행 + 탭으로 구분된 행, 개수 표시 없음기본값. 스트림에 적합하며 유닉스 파이프(cut, awk, wc -l)에도 적합합니다.
json단일 {"columns": [...], "rows": [...]} 객체사용자가 구조화된/기계 출력을 요청하거나, jq로 전달하려는 경우
table열 정렬 ASCII + (N rows) 표시사용자가 사람이 읽을 수 있는 형태 / 복사-붙여넣기 명령을 요청하는 경우

기본 tsv로 시작하십시오. 사용자가 사람이 읽을 수 있거나 구조화된 출력을 요청할 때 --format table 또는 --format json을 제공하십시오 — "이러한 다른 형태도 필요하면 사용할 수 있습니다."

--detail — 필드당 너비, 기본값 snippet

넓은 문자열 필드(특히 messages.text 및 tool_calls.tool_input)는 읽기 시점에 잘리므로 하나의 큰 열이 컨텍스트를 넘치게 하지 않습니다. 잘림은 표시 전용입니다 — 전체 텍스트는 항상 검색 가능합니다.

값필드당 예산사용 시기
compact~40자하나를 선택하기 전에 많은 후보 행을 저렴하게 스캔할 때
snippet (기본값)~120자기본값. 덤프하지 않고 행을 인식하기에 충분합니다.
full제한 없음, 한 줄전체 필드 길이가 필요하고, 한 줄 압축이 괜찮은 경우(테이블/TSV는 안전함)
raw제한 없음, 정확한 공백저장된 그대로의 텍스트가 필요할 때 — 새 줄과 내부 공백이 그대로 유지됩니다. --format json과 함께 선호합니다.

예산을 초과하는 필드는 숨겨진 문자 수를 보고하는 표시자(예: …(+2284))로 생략됩니다. 이 표시자는 더 많은 내용이 존재한다는 신호입니다: 실제로 필요하다면, 특정 행의 해당 필드만 --detail full(길이) 또는 --format json --detail raw(정확한 공백)로 다시 가져오십시오 — 가드레일 참조.

가드레일

이 스킬이 방지하기 위해 존재하는 실패 모드들입니다:

  • 컨텍스트를 폭발시키지 마십시오. 여러 행에 걸쳐 --detail full/raw로 SELECT *(또는 넓은 text 열)를 절대 실행하지 마십시오. 대신: 명시적인 열 목록과 LIMIT으로 --detail compact/snippet으로 좁게 스캔하고, 원하는 행을 식별한 다음, 해당 행의 넓은 필드만 ID에 대한 WHERE로 다시 가져오십시오. 단일 SELECT text FROM messages WHERE message_id = '…'은 저렴합니다. SELECT * FROM messages --detail full은 컨텍스트 폭탄입니다. 정확한 공백(마크다운 테이블, 코드 블록)이 필요하면 --format json --detail raw를 사용하십시오.
  • 읽기 전용입니다 — 쓰기를 시도하지 마십시오. INSERT / UPDATE / DELETE / CREATE는 모두 실패합니다(query failed: …). 다른 표현으로 쓰기를 재시도하지 마십시오; 표면은 조회만 합니다.
  • tool_input은 이질적인 JSON입니다. 키는 도구마다 다릅니다(Shell에는 command, Read에는 path, …). 따라서 순진하게 tool_input->>'key'를 사용하면 캐스트 오류가 발생할 수 있습니다. 서브쿼리/CTE에서 먼저 tool_name을 필터링하고 명시적 함수를 사용하여 안전하게 추출하십시오:
stockroom query "SELECT json_extract_string(tool_input, '\$.command') AS cmd
  FROM (SELECT tool_input FROM tool_calls WHERE tool_name = 'Shell') LIMIT 5"

오류 처리: 반복하지 마십시오

각 실패는 깔끔한 stderr 메시지 + 종료 코드로 전달됩니다 — 읽고 일치하는 조치를 취하십시오. 반복하지 마십시오:

메시지종료의미 / 다음 조치
error: empty query (…)2전달된 SQL이 없습니다. 구문을 제공하십시오.
error: no warehouse found at … — run \stockroom ingest` first`1웨어하우스가 아직 구축되지 않았습니다. 사용자에게 stockroom ingest를 실행하라고 알리십시오(시스템이 설정된 적이 없으면 sr-initialize); 질의를 재시도하지 마십시오.
query failed: …1잘못된 SQL이거나 쓰기가 거부되었습니다. 구문을 수정하십시오(DuckDB 메시지를 읽으십시오) — 동일한 SQL을 다시 실행하지 마십시오.

웨어하우스에 있는 것

먼저 라이브 스키마를 발견하십시오 — 스키마가 진화함에 따라 정확성을 유지합니다:

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

마이그레이션 0001~0008 기준 주요 열에 대한 빠른 참조 (위의 인트로스펙션 질의로 확인):

  • sessions — 대화당 한 행. harness ('cursor'|'claude'), session_id, project_id (프로젝트 디렉터리 슬러그 그대로 — 그룹화 키; Cursor CLI 채팅의 경우 채팅 해시 디렉터리), cwd (실제 경로, NULL일 수 있음), workspace_key (하니스 간 경로 롤업, NULL일 수 있음), entrypoint (알려진 경우 하니스의 표면 출처; NULL일 수 있음 — 리터럴을 추측하지 말고 SELECT DISTINCT entrypoint 사용), models (VARCHAR[], Cursor만 해당), title, git_branch, is_subagent, parent_session_id, started_at, ended_at, source_mtime (마지막 수집 시점의 소스 트랜스크립트 수정 시간), 그리고 네 개의 nullable 세션 단위 토큰 BIGINT (input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens — 하니스가 대화 수준 사용량을 보고하는 경우에만 채워짐; Claude/Cursor는 NULL로 남김). PK (harness, session_id).
  • messages — 턴당 한 행. message_id = '{session_id}#{ordinal}' (하니스 전체에서 균일), parent_id, ordinal, role ('user'|'assistant'), text (전체; 생각은 캡처되지 않음), model (메시지당, Claude만 해당), ts, first_seen_at (stockroom이 메시지를 처음 관찰한 시점), 그리고 네 개의 토큰 BIGINT: input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens (Claude 메시지 사용량; Cursor는 NULL). PK (harness, session_id, message_id).
  • session_token_usage — sessions + 메시지 토큰 합계에 대한 VIEW. 대화 롤업에는 이것을 선호하십시오. 열: *_from_messages (SUM), *_native (세션 열), *_total (COALESCE(native, from_messages)), token_grain ('session'|'message'|'none'). 합계는 보고된 필드의 웨어하우스 롤업이며, 공급업체 청구서가 아닙니다. *_total 위에 메시지 토큰을 추가로 SUM하지 마십시오.
  • tool_calls — 도구 입력만 (출력은 절대 없음). message_id (이를 방출한 턴), ordinal, tool_name, tool_input (이질적인 JSON, 전체 저장됨 — 가드레일 참조). PK (harness, session_id, message_id, ordinal).
  • embeddings — 의미 검색을 위한 청크당 벡터 (owner_table, owner_id, chunk_index, embed_model, vector FLOAT[384]). 직접 질의하는 경우는 드뭅니다 — sr-semantic 스킬을 사용하십시오.
  • _sync_state — 수집 워터마크 기록; 질의할 가치가 없습니다.

조인을 작성하기 전에 알아야 할 한 가지 정체성 규칙: 항상 균일한 message_id / (harness, session_id)로 조인하고, source_* 출처 열로는 절대 조인하지 마십시오. 하니스당 한 단위로만 존재하는 값은 다른 쪽에서 정직하게 NULL입니다(예: messages.model은 Claude 전용; sessions.models은 Cursor 전용; 동일한 이중 단위 정직성이 토큰에도 적용됨).

작업 예제

모두 실제 웨어하우스에서 검증되었습니다.

# 어떤 하니스가 있는가? (tsv 기본값)
stockroom query "SELECT DISTINCT harness FROM sessions ORDER BY harness"

# 하니스별 세션 수, 사용자에게 사람이 읽을 수 있도록:
stockroom query --format table "SELECT harness, count(*) AS n FROM sessions GROUP BY harness ORDER BY n DESC"

# 가장 바쁜 도구:
stockroom query "SELECT tool_name, count(*) AS calls FROM tool_calls GROUP BY tool_name ORDER BY calls DESC LIMIT 5"

# 후보 메시지를 저렴하게 스캔한 다음, 원하는 것을 전체로 다시 가져오기:
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>'"

# 사용자/도구가 사용할 구조화된 출력:
stockroom query --format json "SELECT harness, session_id, title FROM sessions WHERE title IS NOT NULL LIMIT 5"

# 세션별 토큰 롤업 (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"

더 많은 변형(활동 창이 있는 무제한 도구, 일/하니스별 토큰 롤업, 하니스별 스킬 사용 SQL): Cookbook을 참조하십시오.

쿡북

까다로운 시작 SQL: references/cookbook/. 인덱스를 열고 필요한 레시피만 선택하십시오.

사람에게 전달

당신은 도구의 운영자이지, 디스플레이가 아닙니다. SQL을 실행하고, 결과를 읽은 후 사용자에게 자연어로 답변하십시오. 사용자가 보길 요청하지 않는 한, 사람에게 원시 tsv를 붙여넣지 마십시오. 사용자가 원시 출력 — 또는 직접 실행할 명령을 원할 때는 --format table(읽기용) 또는 --format json(처리용) 변형을 제공하십시오.

시스템 이해

이러한 계약이 왜 그런 형태를 가지는지 이해하려면 — 패키징, 토치 계약, 설계상 읽기 전용, 잘림 원칙, 정체성/출처 — 공유 시스템 모델을 읽으십시오: ../sr-search/references/system-model.md.

관련 스킬