ワンクリックで
query
query the lore knowledge graph for sessions, costs, tools, projects, search, and patterns
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
query the lore knowledge graph for sessions, costs, tools, projects, search, and patterns
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
See active Claude Code sessions on this machine and coordinate across them via direct messages, status announcements, and file-overlap awareness. Triggers when the user asks "who else is running?", "any other claude open?", "what other sessions are active?", "tell <name> to ...", "ping <peer>", "let peers know I'm doing X", "broadcast <status>", "check the cc digest", or any cross-session / multi-agent coordination on this machine.
measure your real CC throughput against the time rule's matrix, using lore.db
export the lore knowledge graph or its slices to json, csv, or markdown
explore relationships in the lore knowledge graph - cooccurring files, project sessions, sibling sessions, tagged notes
capture decisions, lessons, reminders, and todos into the lore knowledge graph
walk the user through a low/medium/high effort A/B/C throughput benchmark on their current model
| name | query |
| description | query the lore knowledge graph for sessions, costs, tools, projects, search, and patterns |
| tools | Bash, Read, AskUserQuestion, CronCreate, CronDelete, CronList |
When the user runs /lore (or asks anything that requires reading their session history), interpret their intent and query the lore SQLite database accordingly. The database lives at ~/.claude/lore/lore.db (v2.0+) with a fallback at ~/.claude/mine.db (v1.x). All queries below read from the resolved path.
When constructing sqlite3 queries below, ALWAYS use the absolute path. Bare mine.db or lore.db (without the directory) will create empty stub files in the current working directory. Set DB="$HOME/.claude/lore/lore.db"; [ -f "$DB" ] || DB="$HOME/.claude/mine.db" once at the top of any heredoc and use $DB everywhere.
Run this FIRST:
MISSING=""
command -v sqlite3 >/dev/null 2>&1 || MISSING="$MISSING sqlite3"
command -v python3 >/dev/null 2>&1 || MISSING="$MISSING python3"
if [ -n "$MISSING" ]; then echo "MISSING_DEPS|$MISSING"; exit 0; fi
DB="$HOME/.claude/lore/lore.db"
[ -f "$DB" ] || DB="$HOME/.claude/mine.db"
if [ ! -f "$DB" ]; then echo "NO_DB"; exit 0; fi
LATEST=$(sqlite3 -noheader "$DB" "SELECT MAX(start_time) FROM sessions WHERE is_subagent = 0;" 2>/dev/null)
TOTAL=$(sqlite3 -noheader "$DB" "SELECT COUNT(*) FROM sessions WHERE is_subagent = 0;" 2>/dev/null)
FIRST=$(sqlite3 -noheader "$DB" "SELECT MIN(start_time) FROM sessions WHERE is_subagent = 0;" 2>/dev/null)
NEWEST_JSONL=$(find ~/.claude/projects -name "*.jsonl" -newer "$DB" 2>/dev/null | head -1)
if [ -n "$NEWEST_JSONL" ]; then
echo "STALE|$FIRST|$LATEST|$TOTAL"
for p in ./scripts/mine.py $(find ~/.claude/plugins -path "*/lore/scripts/mine.py" 2>/dev/null | head -1); do
if [ -f "$p" ]; then python3 "$p" --incremental 2>&1; break; fi
done
LATEST=$(sqlite3 -noheader "$DB" "SELECT MAX(start_time) FROM sessions WHERE is_subagent = 0;" 2>/dev/null)
TOTAL=$(sqlite3 -noheader "$DB" "SELECT COUNT(*) FROM sessions WHERE is_subagent = 0;" 2>/dev/null)
FIRST=$(sqlite3 -noheader "$DB" "SELECT MIN(start_time) FROM sessions WHERE is_subagent = 0;" 2>/dev/null)
echo "REFRESHED|$FIRST|$LATEST|$TOTAL"
else
echo "FRESH|$FIRST|$LATEST|$TOTAL"
fi
sqlite3 ships with macOS; python3 via brew/python.org)./scripts/mine.py or search ~/.claude/plugins/*/lore/scripts/mine.py). Use --incremental. If mine.py not found, explain: python3 scripts/mine.py parses ~/.claude/projects/ JSONL logs into ~/.claude/lore/lore.dbDB="$HOME/.claude/lore/lore.db"
[ -f "$DB" ] || DB="$HOME/.claude/mine.db"
CWD_SAFE="${PWD//\'/\'\'}"
MATCH=$(sqlite3 -noheader "$DB" "SELECT project_name, COUNT(*) FROM sessions WHERE (project_dir = '$CWD_SAFE' OR cwd = '$CWD_SAFE') AND is_subagent = 0 GROUP BY project_name ORDER BY COUNT(*) DESC LIMIT 1;" 2>/dev/null)
if [ -z "$MATCH" ]; then
PROJECT=$(basename "$PWD" | tr -dc 'a-zA-Z0-9._-')
MATCH=$(sqlite3 -noheader "$DB" "SELECT project_name, COUNT(*) FROM sessions WHERE project_name = '$PROJECT' AND is_subagent = 0 GROUP BY project_name LIMIT 1;" 2>/dev/null)
fi
echo "SCOPE|$MATCH"
AND project_name = '<project>' to WHERE clausesThree core intents, plus search and freeform. If no argument is given, show the dashboard.
CRITICAL: run ALL queries for an intent in a SINGLE Bash call. Present ONE clean formatted result. NEVER show raw SQL, table names, or intermediate output.
The answer to "what's happening?" Recent activity, where compute goes, whether sessions are productive.
Lore is a dual-source store. Canonical lifetime totals come from Anthropic's pre-computed ~/.claude/stats-cache.json (mirrored into the anthropic_stats table) and exactly match what /usage shows. Per-session detail (messages, tool calls, transcripts) comes from JSONL ingestion and only covers sessions whose JSONLs still exist on disk (CC's 30-day retention). When the user asks for lifetime totals, query anthropic_stats; when they ask for session detail or recent activity, query the sessions/messages tables.
sqlite3 -header -separator '|' "$DB" <<'SQL'
-- canonical lifetime totals (matches /usage)
SELECT 'LIFETIME' s, total_sessions, total_messages, total_tool_calls,
active_days_count, peak_hour, favorite_model, last_computed_date
FROM anthropic_stats
ORDER BY last_computed_date DESC LIMIT 1;
-- coverage: how much of lifetime do JSONL transcripts still cover?
SELECT 'COVERAGE' s,
(SELECT COUNT(*) FROM sessions WHERE is_subagent = 0) lore_main_sessions,
(SELECT COUNT(*) FROM messages) lore_messages,
(SELECT total_sessions FROM anthropic_stats ORDER BY last_computed_date DESC LIMIT 1) anth_sessions,
ROUND(100.0 * (SELECT COUNT(*) FROM sessions WHERE is_subagent = 0) /
NULLIF((SELECT total_sessions FROM anthropic_stats ORDER BY last_computed_date DESC LIMIT 1), 0), 1) coverage_pct;
-- summary (7d, transcript-based for detail)
SELECT 'SUMMARY' s, COUNT(*) sessions,
ROUND(SUM(duration_active_seconds) / 3600.0, 1) active_hrs,
ROUND(SUM(estimated_cost_usd), 2) api_value,
ROUND(SUM(total_cache_read_tokens) * 100.0 / NULLIF(SUM(total_input_tokens + total_cache_creation_tokens + total_cache_read_tokens), 0), 1) cache_pct,
SUM(CASE WHEN compaction_count > 0 THEN 1 ELSE 0 END) compacted,
(SELECT COUNT(*) FROM tool_calls tc JOIN sessions s2 ON tc.session_id=s2.id WHERE s2.is_subagent=0 AND tc.tool_name='Bash' AND tc.input_summary LIKE '%git commit%' AND s2.start_time >= date('now', '-7 days')) commits
FROM user_session_costs WHERE start_time >= date('now', '-7 days');
-- top projects (7d)
WITH ranked AS (
SELECT project_name, COUNT(*) sessions,
ROUND(SUM(estimated_cost_usd), 2) api_value,
ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) rn
FROM user_session_costs
WHERE start_time >= date('now', '-7 days') AND project_name IS NOT NULL
GROUP BY project_name
)
SELECT 'PROJ' s, project_name, sessions, api_value FROM ranked WHERE rn <= 5
UNION ALL
SELECT 'PROJ_OTHER' s, COUNT(*)||' more', SUM(sessions), ROUND(SUM(api_value),2) FROM ranked WHERE rn > 5;
-- session health (7d)
SELECT 'HEALTH' s,
SUM(CASE WHEN tool_use_count > 20 AND (SELECT COUNT(*) FROM tool_calls tc WHERE tc.session_id=user_session_costs.id AND tc.tool_name='Bash' AND tc.input_summary LIKE '%git commit%') = 0 THEN 1 ELSE 0 END) burned,
SUM(CASE WHEN compaction_count > 0 THEN 1 ELSE 0 END) compacted,
COUNT(*) total
FROM user_session_costs WHERE start_time >= date('now', '-7 days');
SQL
Format:
lifetime: <total_sessions> sessions · <total_messages> messages · <active_days> active days · favorite: <model> (from anthropic_stats)transcripts: <lore_main_sessions> of <anth_sessions> sessions (<coverage_pct>%) — older sessions deleted by CC retention sweeprecent data: <first_date> → <latest_date> · scope: <project|global>The answer to "what happened?" Full-text search across every conversation.
TERM='<escaped_search_term>'
sqlite3 -header -separator '|' "$DB" <<SQL
SELECT m.session_id, s.project_name, s.start_time, m.role,
snippet(messages_fts, 0, '>>>', '<<<', '...', 40) AS match
FROM messages_fts
JOIN messages m ON m.id = messages_fts.rowid
JOIN sessions s ON m.session_id = s.id
WHERE messages_fts MATCH '"$TERM"' AND s.is_subagent = 0
ORDER BY m.timestamp DESC LIMIT 20;
SELECT 'TOTAL' s, COUNT(*) total_matches
FROM messages_fts
JOIN messages m ON m.id = messages_fts.rowid
JOIN sessions s ON m.session_id = s.id
WHERE messages_fts MATCH '"$TERM"' AND s.is_subagent = 0;
SQL
Escape single quotes by doubling them. Wrap search term in double quotes inside MATCH to treat as literal phrase. Group results by session. Show: project, date, prompt snippet, match count.
The answer to "am I using this well?" Measures session OUTCOMES, not individual tool errors. A session's health is determined by what it produced, not which commands failed.
sqlite3 -header -separator '|' "$DB" <<'SQL'
-- session outcome classification (last 30 days)
WITH session_outcomes AS (
SELECT
u.id,
u.project_name,
u.start_time,
u.tool_use_count,
u.compaction_count,
u.duration_active_seconds,
ROUND(u.estimated_cost_usd, 2) as api_value,
SUBSTR(u.first_user_prompt, 1, 80) as prompt,
(SELECT COUNT(*) FROM tool_calls tc
WHERE tc.session_id = u.id AND tc.tool_name = 'Bash'
AND tc.input_summary LIKE '%git commit%') as commits,
(SELECT COUNT(DISTINCT tc.input_summary) FROM tool_calls tc
WHERE tc.session_id = u.id AND tc.tool_name IN ('Write','Edit')) as files_mutated
FROM user_session_costs u
WHERE u.start_time >= date('now', '-30 days')
AND u.duration_wall_seconds < 86400
),
classified AS (
SELECT *,
CASE
WHEN commits > 0 THEN 'shipped'
WHEN files_mutated = 0 AND tool_use_count > 5 THEN 'explored'
WHEN tool_use_count > 20 AND commits = 0 AND files_mutated > 0 THEN 'burned'
WHEN tool_use_count <= 5 THEN 'quick'
ELSE 'worked'
END as outcome
FROM session_outcomes
)
SELECT 'OUTCOMES' s, outcome, COUNT(*) n,
ROUND(AVG(api_value), 2) avg_value,
ROUND(AVG(duration_active_seconds / 60.0), 1) avg_active_min
FROM classified GROUP BY outcome ORDER BY n DESC;
-- burned sessions detail (high effort, no commits, wrote files)
SELECT 'BURNED' s, c.project_name, c.start_time, c.tool_use_count tools,
c.compaction_count compactions, c.api_value, c.prompt
FROM (
SELECT so.*,
CASE WHEN so.commits > 0 THEN 'shipped'
WHEN so.files_mutated = 0 AND so.tool_use_count > 5 THEN 'explored'
WHEN so.tool_use_count > 20 AND so.commits = 0 AND so.files_mutated > 0 THEN 'burned'
WHEN so.tool_use_count <= 5 THEN 'quick'
ELSE 'worked' END as outcome
FROM session_outcomes so
) c WHERE c.outcome = 'burned'
ORDER BY c.api_value DESC LIMIT 5;
-- loop detection: files edited 5+ times in a single session (last 30d)
SELECT 'LOOPS' s, s.project_name, tc.input_summary file,
COUNT(*) edits, s.start_time
FROM tool_calls tc
JOIN sessions s ON tc.session_id = s.id
WHERE s.is_subagent = 0 AND tc.tool_name IN ('Write','Edit')
AND tc.input_summary IS NOT NULL
AND s.start_time >= date('now', '-30 days')
GROUP BY tc.session_id, tc.input_summary
HAVING edits >= 5
ORDER BY edits DESC LIMIT 10;
-- compaction as complexity signal
SELECT 'COMPACTION' s,
CASE WHEN duration_wall_seconds < 1800 THEN '<30m'
WHEN duration_wall_seconds < 3600 THEN '30-60m'
ELSE '1hr+' END as bucket,
COUNT(*) sessions,
SUM(CASE WHEN compaction_count > 0 THEN 1 ELSE 0 END) compacted,
ROUND(AVG(compaction_count), 1) avg_compactions
FROM user_session_costs
WHERE start_time >= date('now', '-30 days') AND duration_wall_seconds < 86400
GROUP BY 1 ORDER BY 1;
SQL
Format:
| outcome | what it means | sessions | avg API value | avg active min |
|---|---|---|---|---|
| shipped | committed code | N | $X | Ym |
| explored | read-heavy, no mutations - research | N | $X | Ym |
| burned | wrote files but never committed - effort wasted | N | $X | Ym |
| worked | mutated files, <20 tool calls - small task | N | $X | Ym |
| quick | ≤5 tool calls - trivial | N | $X | Ym |
If the user's question doesn't match dashboard, search, or health - use the schema to construct a read-only SELECT query. Claude is great at this. Just follow the rules.
Schema reference (key tables and views):
| table/view | what it has |
|---|---|
sessions | id, project_name, model, start_time, duration_wall_seconds, duration_active_seconds, tool_use_count, compaction_count, first_user_prompt, is_subagent |
tool_calls | session_id, tool_name, input_summary, timestamp |
errors | session_id, tool_name, error_message, timestamp |
subagents | parent_session_id, agent_type, duration_seconds, tool_use_count |
messages | session_id, role, content_preview, input_tokens, output_tokens, cache_read_tokens |
messages_fts | FTS5 full-text index on messages (use MATCH) |
user_session_costs | main view - sessions with costs, durations, tokens (is_subagent=0, valid model) |
user_tool_calls | tool calls with project_name (main sessions only) |
project_costs | per-project aggregates |
daily_costs | per-day aggregates |
session_costs | per-session cost with model pricing applied |
Common freeform queries people ask:
NEVER write to the database. NEVER show SQL to the user. If a query fails, describe what data was unavailable, not which table was missing.
estimated_cost_usd is the API inference value - what usage would cost at per-token rates. Most Claude Code users are on a subscription.
| plan | price | notes |
|---|---|---|
| Pro | $20/month | usage-limited |
| Max 5x | $100/month | 5x Pro allowance |
| Max 20x | $200/month | 20x Pro allowance |
| API direct | per-token | billed at published rates |
$2,055 API value → 103x Pro · 21x Max 5x · 10x Max 20xdata: <first_date> → <latest_date> · scope: <project|global>