Skip to content
Back to skills

Graph

ASecurity

explore relationships in the lore knowledge graph - cooccurring files, project sessions, sibling sessions, tagged notes

  • 28 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 3, 2026
developmentpythonshellbashsqlnodedatabase

Works with

  • claude code

Security analysis

A100/100

Scanned September 3, 2026

npx -y skills add anipotts/coding-agent-tips --skill graph --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Graph?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Graph
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/anipotts-graph-coding-agent-tips/badge)](https://www.skillsdirectory.com/skills/anipotts-graph-coding-agent-tips)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: graph
description: explore relationships in the lore knowledge graph - cooccurring files, project sessions, sibling sessions, tagged notes
tools: Bash, Read, AskUserQuestion
---
<!-- tested with: claude code v2.1.122 -->

When the user runs `/lore:graph`, surface relationships derived from their session history. Unlike `/lore` (which is a dashboard / freeform query) this skill is *graph-shaped*: nodes are sessions, files, projects, tools, and notes; edges are cooccurrence, parent-child, and tags.

## locate the database

`````bash
DB="$HOME/.claude/lore/lore.db"
[ -f "$DB" ] || DB="$HOME/.claude/mine.db"
if [ ! -f "$DB" ]; then echo "no lore.db -- run /lore once to seed it"; exit 0; fi
`````

If the database doesn't exist, tell the user to run `/lore` once (which auto-backfills) and stop.

## intents

| user phrasing | edge type | query |
|---|---|---|
| "what files appear with X", "what cooccurs with X", "neighbors of X" | file cooccurrence | see `cooccurrence` below |
| "show project graph for X", "files in project X" | project → files | see `project_files` below |
| "sibling sessions to X", "what came before/after X" | session sequencing | see `siblings` below |
| "notes about X", "tagged X" | notes | call `notes.py search "X"` or `notes.py list --tag X` |
| "graph for this file" (no args, in a file) | cooccurrence on cwd file | resolve the active file path, then `cooccurrence` |
| "summary", no args | global graph stats | see `summary` below |

## queries

All queries use parameterized SQL via a small Python heredoc. This matches the convention used in `notes.py` and `/lore:export` -- no shell-string interpolation into SQL, so paths/projects with apostrophes or special characters work correctly.

### cooccurrence

Resolve the user's "file" argument loosely -- they'll often give a short name (`hook.py`) when the DB has absolute paths. Use a LIKE match.

`````bash
TARGET="$1"  # e.g. "hook.py" or "/abs/path/to/file"
python3 - "$DB" "$TARGET" <<'PY'
import sqlite3, sys
db = sqlite3.connect(sys.argv[1])
needle = f"%{sys.argv[2]}%"
rows = db.execute("""
  SELECT CASE WHEN file_a LIKE ? THEN file_b ELSE file_a END AS neighbor,
         session_count, last_seen
  FROM file_cooccurrences
  WHERE file_a LIKE ? OR file_b LIKE ?
  ORDER BY session_count DESC LIMIT 20
""", (needle, needle, needle)).fetchall()
if not rows:
    print(f"no neighbors for '{sys.argv[2]}'")
else:
    for r in rows: print(f"  {r[1]:>4}  {r[0]}  ({r[2]})")
PY
`````

If the LIKE returns nothing, try a wider match (basename only) before saying "no neighbors".

### project_files

`````bash
PROJECT="$1"
python3 - "$DB" "$PROJECT" <<'PY'
import sqlite3, sys
db = sqlite3.connect(sys.argv[1])
rows = db.execute("""
  SELECT tc.input_summary AS file, COUNT(DISTINCT tc.session_id) AS sessions,
         MAX(tc.timestamp) AS last_touched
  FROM tool_calls tc JOIN sessions s ON tc.session_id = s.id
  WHERE s.project_name = ?
    AND tc.tool_name IN ('Edit','Read','Write','MultiEdit')
    AND tc.input_summary IS NOT NULL
  GROUP BY tc.input_summary ORDER BY sessions DESC LIMIT 25
""", (sys.argv[2],)).fetchall()
if not rows:
    print(f"no files in project '{sys.argv[2]}'")
else:
    for r in rows: print(f"  {r[1]:>4}  {r[0]}  ({r[2]})")
PY
`````

### siblings

Sibling sessions = sessions in the same project, ordered by start_time, with the target session in the middle. Useful for "what was I doing right before/after this".

`````bash
SESSION_ID="$1"
python3 - "$DB" "$SESSION_ID" <<'PY'
import sqlite3, sys
db = sqlite3.connect(sys.argv[1])
target = db.execute("SELECT project_name, start_time FROM sessions WHERE id = ?", (sys.argv[2],)).fetchone()
if not target:
    print(f"session {sys.argv[2]} not found"); sys.exit(0)
rows = db.execute("""
  SELECT id, start_time, first_user_prompt FROM sessions
  WHERE project_name = ? AND is_subagent = 0
  ORDER BY ABS(strftime('%s', start_time) - strftime('%s', ?)) LIMIT 5
""", (target[0], target[1])).fetchall()
for r in rows: print(f"  {r[1]}  {r[0][:8]}  {(r[2] or '')[:80]}")
PY
`````

### summary

The summary query takes no user input, so a plain sqlite3 invocation is fine.

`````bash
sqlite3 -header -column "$DB" <<'SQL'
SELECT
  (SELECT COUNT(*) FROM sessions WHERE is_subagent = 0) AS sessions,
  (SELECT COUNT(DISTINCT project_name) FROM sessions WHERE project_name IS NOT NULL) AS projects,
  (SELECT COUNT(DISTINCT input_summary) FROM tool_calls WHERE tool_name IN ('Edit','Read','Write','MultiEdit') AND input_summary IS NOT NULL) AS distinct_files,
  (SELECT COUNT(*) FROM file_cooccurrences) AS file_pairs,
  (SELECT COUNT(*) FROM notes) AS notes;
SQL
`````

## scoping

Default to global. If the user is inside a project that exists in `sessions.project_name`, mention it ("scoped to <project>; say 'global' to widen") and add a `WHERE project_name = ...` filter where it makes sense.

## output

`sqlite3 -header -column` already produces clean tables -- pass them through. If a result is large (>30 rows), summarize counts at the bottom rather than dumping everything. If the query returns zero rows, suggest an alternative ("no neighbors for `hook.py` in your history; try `/lore:graph project lore` instead").

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.