Tool Usage
The tool-monitor database records every Claude Code tool invocation.
Database: ~/.claude/tool-monitor.sqlite
tool_events table
| Column | Type | Notes |
|---|---|---|
id |
INTEGER | Primary key |
session_id |
TEXT | Groups events by conversation session |
hook_event_name |
TEXT | PreToolUse, PostToolUse, PostToolUseFailure, or PermissionRequest |
tool_name |
TEXT | e.g. Bash, Read, Grep, Edit, Write, Glob, Task |
cwd |
TEXT | Working directory at time of invocation |
transcript_path |
TEXT | Path to the session transcript file |
created_at |
DATETIME | Timestamp |
payload |
TEXT | Full JSON payload (all fields above, plus tool_input and more) |
Tool-specific input fields live inside payload and are accessed with json_extract:
json_extract(payload, '$.tool_input.command') -- Bash: the shell command
json_extract(payload, '$.tool_input.file_path') -- Read/Write: file path
json_extract(payload, '$.tool_input.pattern') -- Grep: search pattern
json_extract(payload, '$.tool_input.old_string') -- Edit: text being replaced
Discovering fields for any tool
To see what tool_input fields are available for a specific tool, query tool_schemas:
SELECT json_extract(schema_json, '$.properties.tool_input.properties')
FROM tool_schemas
WHERE tool_name = 'Bash' AND hook_event = 'PreToolUse';
To list all tracked tools and their categories:
SELECT DISTINCT tool_name, category FROM tool_schemas WHERE hook_event = 'PreToolUse' ORDER BY tool_name;
FTS5 wildcard and substring search
For substring and wildcard searches, FTS5 virtual tables are far faster than
LIKE '%term%' on large databases (typically 100-700x).
The database is self-describing: query tool_schemas.indexed_fields to discover
which tools have FTS coverage and which tables and columns to use:
SELECT tool_name,
indexed_fields
FROM tool_schemas
WHERE hook_event = 'PreToolUse'
AND indexed_fields != '[]'
ORDER BY tool_name;
Each indexed_fields value is a JSON array of {"path", "fts_table", "fts_column"} objects.
Use fts_table and fts_column from those results to build the JOIN:
SELECT e.created_at, json_extract(e.payload, '$.tool_input.command')
FROM tool_events e
JOIN fts_bash_command f ON f.event_id = e.id
WHERE f.command MATCH '"git commit"'
ORDER BY e.created_at DESC;
Special characters (., -, /) require phrase quoting: MATCH '"CLAUDE.md"' not MATCH 'CLAUDE.md'
Use json_extract with = for exact equality (hits expression indexes). Use FTS5 MATCH
for substring or wildcard search.
Running queries
Before querying, verify the database exists:
test -f ~/.claude/tool-monitor.sqlite || echo "Database not found — is tool-monitor installed and running?"
sqlite3 ~/.claude/tool-monitor.sqlite "<SQL>"
Use .mode column and .headers on for readable tabular output:
sqlite3 -column -header ~/.claude/tool-monitor.sqlite "<SQL>"
Two-step workflow for tool-specific queries
When the user asks about a specific tool's inputs (e.g. "which files have I read?", "what bash commands containing git?"), first look up the field names, then query:
- Look up fields:
SELECT json_extract(schema_json, '$.properties.tool_input.properties') FROM tool_schemas WHERE tool_name = 'Read' AND hook_event = 'PreToolUse'; - Query events:
SELECT json_extract(payload, '$.tool_input.file_path'), created_at FROM tool_events WHERE tool_name = 'Read' ORDER BY created_at DESC LIMIT 20;
Common patterns
Filter by text pattern:
WHERE json_extract(payload, '$.tool_input.command') LIKE '%git%'
Scope to a directory:
WHERE cwd LIKE '/path/to/my-project%'
Scope to current session:
WHERE session_id = (SELECT session_id FROM tool_events ORDER BY created_at DESC LIMIT 1)
Activity today:
WHERE date(created_at) = date('now')
Tool frequency summary:
SELECT tool_name, COUNT(*) AS uses
FROM tool_events
WHERE hook_event_name = 'PreToolUse'
GROUP BY tool_name
ORDER BY uses DESC;
Cross-referencing session transcripts
Session JSONL hook_progress entries log a compound hookName field in the
format {hookEvent}:{tool_name} (e.g. PreToolUse:ExitPlanMode). The
tool-monitor database stores these as separate columns, so to find the
corresponding entry, query by hook_event_name and tool_name independently:
SELECT id, hook_event_name, tool_name, created_at
FROM tool_events
WHERE hook_event_name = 'PreToolUse'
AND tool_name = 'ExitPlanMode'
AND session_id = '32dff3bf-c7e7-4ef8-a9a3-53f7c7b65917';
Note: the matcher regex from hook configuration (e.g. "*", "Bash") does
not appear in the database. The tool_name column always holds the actual
tool that triggered the hook, regardless of which matcher matched it.