Skip to main content

slurp logo

slurp

tests python license pypi

graphify builds the bowl. slurp serves exactly the noodles your LLM needs.

A knowledge graph is a bowl of ramen — thousands of nodes tangled together. Your LLM doesn't need the whole bowl. Slurp scores every node against your query, then greedily selects the highest-relevance subgraph that fits within your token budget — and tells you exactly what it picked and why. Works standalone or as a companion to graphify.


Benchmark

Tested on a real PrismaStats codebase: 2,111 nodes, 28,412 tokens total.

Query Budget 2k Budget 4k Budget 8k
"auth flow" 97.1% saved 96.3% saved 95.2% saved
"prisma schema" 95.8% saved 94.2% saved 93.8% saved
"database pool" 93.1% saved 89.1% saved 85.1% saved

Mean savings: 93.3% · p50: 94.2% · Best case: 97.1%

Even the worst case — "database pool" at budget 8k — injects 85% fewer tokens than the full graph.


Performance

Measured on the same PrismaStats graph (2,111 nodes, 3,421 edges), 10 hot queries through the real MCP handler with time.perf_counter:

Optimization Before After Improvement
PageRank cache 8.32 ms 0.002 ms 4000×
Token count cache ~50 ms 0.174 ms 280×
Greedy heap (O(n log n)) 63.78 ms 10.69 ms
End-to-end latency 86.41 ms 10.69 ms 8.1×
Graph staleness silent auto-reload

PageRank cache — PageRank depends only on the graph, never on the query, so it is computed once per graph object instead of once per query.

Token count cache — per-node token costs are memoised across queries, keyed by (node_id, encoding). The graph's text does not change between queries, so neither does its token cost.

Greedy heap — the subgraph selector used to scan every remaining candidate on each iteration, which is O(n²). It now uses a lazy max-heap: scores still mutate as neighbors get boosted, so a boost pushes a fresh entry and superseded entries are discarded when they surface. Ties break by node id, which also makes the selection deterministic — the previous scan broke ties by set iteration order, so the same query could return a different subgraph on every process start.

Graph staleness — the MCP server records the graph file's mtime and reloads it when it changes on disk, invalidating both caches. Before, a server started before a re-index would keep answering from the graph it read at boot, with no way for the client to know. Responses that triggered a reload carry "graph_reloaded": true.


Install

Quick reference:

Situation Command
Any project, fastest setup uv tool install slurp-graph
Non-Python project (pipx user) pipx install slurp-graph
Simple global install pip install slurp-graph
Python project (adds to pyproject.toml) uv add slurp-graph
Better TypeScript/TSX indexing pip install "slurp-graph[ts]"

Requires Python 3.12+. Don't have Python? Install uv — it bundles a Python runtime and is the fastest path.


Install uv (if you don't have Python yet):

# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Then: uv tool install slurp-graph


Non-Python projects (JS, TypeScript, Go — install slurp globally so it's on your PATH):

uv tool install slurp-graph     # recommended: isolated environment, no conflicts
pipx install slurp-graph        # same idea if you already have pipx
pip install slurp-graph         # works if Python's bin/Scripts dir is on your PATH

Windows: pip install places slurp.exe in Python's Scripts folder, which may not be on PATH by default. If slurp is not found after install, see adding Python Scripts to PATH, or use uv tool install instead (it handles PATH automatically).


Python projects (adds slurp as a project dependency):

uv add slurp-graph
# or
pip install slurp-graph

When using uv add, run slurp as uv run slurp or activate the virtual environment first. For the MCP server with uv add, see the note in MCP Integration.


PyPI package: slurp-graph — CLI command: slurp

📖 Full usage guide (automatic MCP mode + manual CLI): USAGE.md


Quickstart

New to slurp? Run slurp init in your project root — it detects your language, indexes your codebase, and configures the MCP server in one step.

slurp init

Then query it:

slurp "auth flow" --graph graph.json --budget 4000
╭─ Slurp — Subgraph for: "auth flow" (budget: 4,000 tokens) ──────────────╮
│ Selected 5/2111 nodes · 847/4,000 tokens used (21.2%)                    │
╰───────────────────────────────────────────────────────────────────────────╯

## Relevant Nodes

### authenticate_user (function) · score: 0.94
Validates user credentials and returns JWT token.
→ File: src/auth/service.py

### JWTMiddleware (class) · score: 0.87
Intercepts HTTP requests and validates Authorization header.
→ File: src/middleware/jwt.py

### hash_password (function) · score: 0.71
Hashes password using bcrypt with a cost factor of 12.
→ File: src/auth/utils.py

## Key Relationships
- JWTMiddleware → calls → authenticate_user
- authenticate_user → calls → hash_password

---
💡 2106 additional connected nodes available — increase --budget to include them

Add --inject-code to embed the actual function body next to each node:

slurp "auth flow" --graph graph.json --budget 4000 --inject-code
### authenticate_user (function) · score: 0.94
Validates user credentials and returns JWT token.
→ File: src/auth/service.py

```python
def authenticate_user(username: str, password: str) -> dict | None:
    user = db.query(User).filter_by(username=username).first()
    if not user or not bcrypt.checkpw(password.encode(), user.password_hash):
        return None
    return {"token": jwt.encode({"sub": user.id}, SECRET_KEY)}
```

Pipe the output directly into your LLM prompt, save it to a file, or use slurp export to format it as a ready-to-paste system prompt block.


Commands

slurp init

Guided one-command setup. New to slurp? Run slurp init in your project root — it detects your language, indexes your codebase, and configures the MCP server in one step.

slurp init          # from your project root — no flags needed
slurp init --yes    # accept every prompt (CI / scripting)

It shows you a plan and asks for confirmation before touching anything:

  1. Detects the dominant language by counting .py, .ts, .tsx, .js, .jsx and .go files, ignoring vendored trees like node_modules/ and .venv/.
  2. Indexes the project into graphify-out/graph.json with a live progress bar. If a graph already exists, it offers to reuse it instead of re-indexing.
  3. Writes .mcp.json pointing at the slurp binary it detected — works with both uv tool install and pip install layouts. An existing .mcp.json is never clobbered: slurp asks first, and other MCP servers in the file are preserved.

Finish by restarting your AI coding assistant to activate slurp.

Flag Default Description
--yes, -y off Accept every confirmation prompt. Useful for CI and scripting.

slurp QUERY

The main command. Scores all graph nodes against your query and selects the optimal subgraph within the token budget.

slurp "auth flow" --graph graph.json --budget 4000
slurp "payment processing" --format json
slurp "JWT validation" --explain
slurp "database schema" --inject-code --min-score 0.3
slurp "prisma models" --backend openai
Flag Default Description
--graph, -g auto-discover Path to graph.json. Repeatable — see federation.
--graph-label derived from path Project name for each --graph, in the same order.
--budget, -b 4000 Token budget for subgraph selection.
--format, -f markdown Output format: markdown, json, or yaml.
--model, -m cl100k_base Tiktoken encoding for token counting.
--explain off Print per-node score breakdown: final / structural / semantic.
--no-audit off Skip writing to .slurp/audit.jsonl.
--neighbor-decay 0.7 Score multiplier applied to neighbors of each selected node.
--min-score 0.15 Minimum relevance score; nodes below this are excluded before selection.
--viz off Open an interactive graph visualization in the browser.
--viz-output PATH Save visualization HTML to file (without opening browser).
--ignore-file .slurpignore Path to node exclusion rules.
--backend tfidf Scoring backend: tfidf (default), openai, or anthropic.
--inject-code off Embed source code blocks for each selected node (requires ≤30 nodes).
--project-root graph dir Root directory for resolving source_file paths.

Auto-discovery (when --graph is omitted):

  1. ./graph.json
  2. ./graphify-out/graph.json
  3. ./.graphify/graph.json

Multi-graph federation

Query across multiple codebases simultaneously.

A system split across repos is still one system, but slurp normally sees one graph at a time — a question about "auth flow" stops at the boundary of whichever repo you pointed it at. Pass --graph more than once to merge them into a single queryable graph:

slurp "auth flow" --graph services/auth/graph.json --graph services/api/graph.json
Federated: 2 graphs · 4,521 nodes total

╭─ Slurp — Subgraph for: "auth flow" (budget: 4,000 tokens) ─╮
│ Selected 12/4521 nodes · 1,204/4,000 tokens used (0.3%)    │
╰────────────────────────────────────────────────────────────╯

Node ids are namespaced automatically. Two services can both define main or authenticate_user without one silently overwriting the other — every id is prefixed with its project, as auth::authenticate_user. If any original ids did appear in more than one graph, slurp says so:

  3 node ids appeared in more than one graph — namespaced by project, none lost.

Project names come from the graph paths by default. Since most projects keep their graph at <project>/graphify-out/graph.json — where every file stem is just graph — slurp walks up the path for a name that actually identifies the project. Override it with --graph-label, one per --graph, in the same order:

slurp "auth flow" \
  --graph services/auth/graphify-out/graph.json \
  --graph services/api/graphify-out/graph.json \
  --graph apps/web/graphify-out/graph.json \
  --graph-label auth --graph-label api --graph-label frontend

The MCP server federates too, so your AI assistant can query every service at once through the same slurp_query tool. Responses carry graphs_count when more than one graph is being served:

slurp serve --graph services/auth/graph.json --graph services/api/graph.json

In --viz, federated nodes show a Project field in the detail panel, and the legend gains a Projects section listing every project on screen.

One graph behaves exactly as before — no prefixes, no _project attribute, no federation header. Federation only engages from the second --graph onward.

Merging does not invent edges between projects: if api imports auth, that relationship exists in neither graph.json, so slurp does not fabricate it. Each project stays internally connected, and neighbor expansion does not cross project boundaries.


slurp stats

Print node and edge counts for a graph file.

slurp stats --graph graph.json
Graph: graph.json
Nodes: 2111
Edges: 4823

slurp audit

Show the history of queries logged to .slurp/audit.jsonl, plus the most frequently selected nodes.

slurp audit
slurp audit --top-nodes 20
slurp audit --audit-dir /custom/.slurp

Every query is appended as a JSON line (unless --no-audit is passed). Useful for tracking which parts of your codebase an AI agent visits most.


slurp advisor

Recommends the optimal token budget based on your query history.

Guessing at --budget costs you either way: too low truncates the answer, too high pays for nodes the LLM never reads. Once .slurp/audit.jsonl holds a few dozen entries, the right number is already in your data — the advisor finds the past queries that resemble the new one and reads the budget off what they actually used.

slurp advisor "auth flow" --graph graph.json
╭──────────────── Budget Advisor — "auth flow" ────────────────╮
│ Based on 12 similar past queries                             │
╰──────────────────────────────────────────────────────────────╯

Recommended budget:  2,840 tokens
Expected coverage:   99.3% of similar queries' selections
Estimated cost:      $0.0085  (claude-sonnet-5)
Confidence:          HIGH  (12 similar queries)

Similar past queries:
  "auth flow cookie" → 2,770 tokens · 97.4% savings
  "auth flow guard"  → 2,680 tokens · 97.5% savings
  "auth flow jwt"    → 2,750 tokens · 97.4% savings
  "auth flow login"  → 2,650 tokens · 97.5% savings
  "auth flow logout" → 2,620 tokens · 97.5% savings
  … and 7 more

Run with recommended budget:
  slurp "auth flow" --graph graph.json --budget 2840
Flag Default Description
--graph, -g auto-discovered Path to graph.json, used in the suggested command line.
--audit-dir .slurp Directory containing audit.jsonl.
--price-model claude-sonnet-5 Pricing model for the cost estimate (same models as slurp benchmark).
--min-similar 3 Similar queries needed before a recommendation is considered confident.

How it works. Past queries are tokenized with the same tokenizer used to score nodes — so authFlow, auth_flow and auth flow are one ask — and compared by TF-IDF cosine similarity. Anything at or above 0.3 counts as similar. The recommended budget is the 75th percentile of what those queries actually consumed: it fits three out of four comparable queries, where the mean would under-serve the heavier half and the max would pay for one outlier every time.

Confidence Meaning
HIGH 10+ similar queries
MEDIUM at least --min-similar (default 3)
LOW fewer than --min-similar — still recommends, with a warning
NONE no similar history — falls back to the 4,000-token default

Savings percentages are estimated against a baseline of ~50 tokens per node, the same baseline the visualizer uses. The audit log records outcomes, not the full-graph token count, so no historical graph needs to still exist on disk.


slurp explain

Explains any node in natural language — what it does, its architecture, and the risk of changing it.

slurp explain "recalcularPlayerStats" --graph graph.json
╭──────────────── slurp explain — recalcularPlayerStats() ────────────────╮
│ function · lib/supabase/admin-actions.ts · score: 0.966                 │
╰─────────────────────────────────────────────────────────────────────────╯

EXPLANATION
recalcularPlayerStats() is a core admin-side function that recomputes player
statistics from scratch by aggregating raw match event data, likely to keep
derived stats (goals, cards, appearances, etc.) consistent whenever underlying
match data changes. It exists as a shared recalculation routine so that any
operation touching match events — inserts, deletions, substitutions, imports,
or scheduled jobs — can trigger a fresh, authoritative recompute rather than
each caller maintaining its own incremental update logic.

Given its high blast radius, any change to this function's logic, signature, or
side effects could silently break stats recalculation across eight distinct
workflows, making regressions here likely to propagate broadly and be hard to
detect until stats appear wrong.

ARCHITECTURE
→ Called by: adminBackfill(), deleteMatchEventAdmin(),
             importMatchCsv(), insertMatchEventAdmin(),
             insertSubstitutionEventAdmin(), nightlyStatsJob(),
             recalcTeamTable(), refreshAllStats()
← Calls: createAdminClient()

RISK IF CHANGED: HIGH
8 nodes depend on this function directly.

─────────────────────────────────────────────────────────────────────────
Provider: anthropic (claude-sonnet-5) · Context: 198 tokens
Flag Default Description
--graph, -g auto-discovered Path to graph.json.
--provider auto-detected anthropic, openai, ollama, or openai-compatible.
--model, -m per-provider default Model name.
--endpoint Base URL for the openai-compatible provider.
--no-llm off Skip the LLM and show the structural analysis only.
--hops 2 Neighbourhood radius used to build the explanation context.

Providers. With no --provider, slurp auto-detects in this order:

Provider Detected via Default model Notes
anthropic ANTHROPIC_API_KEY claude-sonnet-5 Needs pip install anthropic.
openai OPENAI_API_KEY gpt-4o-mini Needs pip install openai.
ollama server answering on localhost:11434 llama3.2 Fully local, no API key.
openai-compatible SLURP_LLM_ENDPOINT (+ optional SLURP_LLM_API_KEY) local-model LM Studio, Together, Groq, vLLM, anything speaking the OpenAI API.

If none are present, slurp uses the structural explanation — a deterministic description built from the graph alone. It is always produced first, so a missing SDK, an absent API key, or an unreachable endpoint degrades to it rather than failing:

Provider: structural · Context: 198 tokens
Note: openai-compatible unavailable (Could not reach http://localhost:1234/v1/chat/completions:
      [Errno 61] Connection refused); showed structural analysis

Force it with --no-llm to get an offline, zero-cost explanation.

Architecture and risk are always computed from the graph, never written by the model. The LLM contributes only the prose under EXPLANATION; callers, callees, and blast radius are facts slurp already has, so the model is explicitly told not to restate them.

Works best with graphs that include call edges (graphify). With slurp index graphs, callers are inferred from contains edges — a symbol's only "caller" is the module that declares it, so the risk level will read LOW for almost everything.


slurp config

Saves LLM settings to .slurp/config.json so you don't pass flags every time.

slurp config set provider openai-compatible
slurp config set model qwen2.5-coder
slurp config set endpoint http://localhost:1234/v1
slurp config set api_key sk-...        # stored, never echoed back
slurp config show
   slurp config — .slurp/config.json
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Key      ┃ Value                    ┃
┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ api_key  │ ********                 │
│ endpoint │ http://localhost:1234/v1 │
│ model    │ qwen2.5-coder            │
│ provider │ openai-compatible        │
└──────────┴──────────────────────────┘

Effective provider: openai-compatible
Effective model:    qwen2.5-coder
Effective endpoint: http://localhost:1234/v1

Keys: provider, model, endpoint, api_key, temperature. Precedence is flags → saved config → environment auto-detection, so an explicit flag is never overridden by a stored preference. slurp config show prints both what is saved and what slurp would actually use right now.

api_key is masked in all output but stored in plain text in .slurp/config.json — keep .slurp/ out of version control, or leave the key in an environment variable instead.


slurp diff

Know exactly what changed — and what it affects.

A git diff tells you which lines moved. It cannot tell you that the helper you just renamed is called from eleven other modules, or that the function you deleted was the only caller keeping a service alive. slurp diff compares two versions of your knowledge graph and reports the blast radius: what changed, what sits downstream of it, and which nodes are central enough that a reviewer should look at them by hand.

The workflow: before you merge

Index both sides of the change and diff them:

git checkout main       && slurp index . --output main.json
git checkout feature/auth-refactor && slurp index . --output feature.json

slurp diff main.json feature.json --viz

The --viz flag opens an interactive graph where the change is colour-coded: green for added nodes, red for removed, yellow for modified, and grey for untouched neighbors that are still connected to the change. You can see at a glance whether your refactor touched one isolated corner or pulled on a thread running through half the codebase.

Text output

Without --viz you get a Markdown impact report — pipe it into a PR description, a review checklist, or your AI assistant:

# Slurp Diff — Impact Analysis

## Summary
- **⚠️ High impact change**
- **Impact score:** 0.7412 (🔴 high)
- 3 nodes added · 1 removed · 2 modified
- 5 edges added · 2 removed
- 9 nodes in risk neighborhood

## Added Nodes (3)

### refresh_token (function)
Issues a new JWT from a valid refresh token.
→ File: src/auth/tokens.py

## Removed Nodes (1)

### legacy_session_check

## Modified Nodes (2)

### authenticate_user (function)
### JWTMiddleware (class)

## Affected Edges

**Added (5):**
- login_handler → calls → refresh_token
- JWTMiddleware → calls → refresh_token

**Removed (2):**
- login_handler → legacy_session_check

## Nodes at Risk
Direct neighbors of changed nodes:

- login_handler (function) · centrality: 0.0841
- UserModel (class) · centrality: 0.0663
- api_router (module) · centrality: 0.0512

## What to review
Most connected nodes in the blast radius — review these first:

1. login_handler (function) · centrality: 0.0841 · src/api/login.py
2. UserModel (class) · centrality: 0.0663 · src/models.py
3. api_router (module) · centrality: 0.0512 · src/api/router.py
4. JWTMiddleware (class) · centrality: 0.0447 · src/middleware/jwt.py
5. authenticate_user (function) · centrality: 0.0391 · src/auth/service.py

The run finishes with a colour-coded summary panel and, if you did not pass --viz, the exact command to see the full picture:

╭─────────────── Impact Summary ───────────────╮
│                                              │
│  ⚠️ High impact change  (impact score 0.7412) │
│                                              │
│  +3 added  -1 removed  ~2 modified           │
│                                              │
│  See the full blast radius:                  │
│    slurp diff main.json feature.json --viz   │
│                                              │
╰──────────────────────────────────────────────╯

Flags

slurp diff old.json new.json
slurp diff old.json new.json --hops 2 --viz
slurp diff old.json new.json --budget 4000
slurp diff old.json new.json --viz-output reports/impact.html
Flag Default Description
--hops 2 Depth of impact neighborhood expansion.
--viz off Open an interactive visualizer of the affected area in the browser.
--viz-output PATH Save visualization HTML to file (without opening browser).
--budget, -b none Token budget; selects the most relevant nodes from the affected area.

Impact score is computed from the centrality of the changed nodes — changing a leaf scores near zero, changing a hub scores high. --hops controls how far the blast radius is traced; --budget narrows the affected area down to what fits a token budget, so you can hand exactly the relevant slice to a reviewer or an LLM.

This is the only tool that shows you the blast radius of your code changes before you merge.


slurp export

Export a context block ready to paste into an AI system prompt.

slurp export "auth flow" --format claude     # <context> XML tags
slurp export "auth flow" --format chatgpt    # [CODEBASE CONTEXT] block
slurp export "auth flow" --format claudemd   # ## Codebase Context for CLAUDE.md
slurp export "auth flow" --output context.md

All three formats include query, nodes selected/total, tokens used/budget, and coverage %.


slurp serve

Start an MCP stdio server (JSON-RPC 2.0) that exposes the slurp_query tool.

slurp serve --graph graph.json
slurp serve --graph graph.json --no-log
Flag Default Description
--graph, -g auto-discover Path to graph.json. Repeatable — see federation.
--graph-label derived from path Project name for each --graph, in the same order.
--log / --no-log --log Append served queries to .slurp/session.log (only if .slurp/ exists).

See MCP Integration for configuration.


slurp session

Shows queries processed by the MCP server in real time.

slurp session --last 10
slurp session --tail
Flag Default Description
--last N 20 Number of most recent entries to show.
--tail off Follow the log in real time (Ctrl+C to stop).
--log-dir PATH .slurp Directory containing session.log.
             MCP Session Log — last 2 (.slurp/session.log)
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━┳━━━━━━━━┳━━━━━━━━━┓
┃ Time                ┃ Query      ┃ Budget ┃ Nodes ┃ Tokens ┃ Savings ┃
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━╇━━━━━━━━╇━━━━━━━━━┩
│ 2026-08-15T12:13:58 │ auth flow  │  4,000 │   171 │  4,000 │   94.6% │
│ 2026-08-15T12:13:58 │ mcp server │  2,000 │    94 │  1,995 │   97.3% │
└─────────────────────┴────────────┴────────┴───────┴────────┴─────────┘

Use it to confirm your AI assistant is actually calling slurp. The log is written only when .slurp/ already exists — running any query manually creates it, and slurp serve --no-log turns logging off entirely.


slurp benchmark

Measure real token savings across queries and budgets.

slurp benchmark \
  --graph graph.json \
  --queries "auth flow" --queries "schema validation" \
  --budget 2000 --budget 4000 --budget 8000
# Windows CMD: remove the backslashes and write on one line

Outputs a per-run table and aggregate stats: mean savings, p50/p90/p95, best/worst case, and precision (fraction of relevant nodes captured).


slurp index

Index the project's source code and generate graph.json without graphify or any LLM.

slurp index .                              # index current directory
slurp index /path/to/project              # specific path
slurp index . --output custom/graph.json  # custom output path
slurp index . --watch                     # re-index on file changes
slurp index . --smart                     # only re-index what changed
Indexing /path/to/project ...
✓ 312 nodes · 487 edges · 41 files
  Saved: /path/to/project/graphify-out/graph.json

Next: slurp "your query" --graph /path/to/project/graphify-out/graph.json
Flag Default Description
--output, -o <path>/graphify-out/graph.json Output path for graph.json.
--watch off Re-index on file changes (requires watchdog, installed by default).
--smart off Git-aware incremental re-index — only re-indexes changed files and their dependents.
--dry-run off Show what --smart would re-index without making changes.
--ignore-file .slurpignore Path to .slurpignore rules.

Incremental re-indexing with --smart

Re-parsing every file after a two-line edit is wasted work. --smart asks git which files changed since the last commit — unstaged, staged, and untracked — widens that set to the files that import them (2 hops), and rewrites only that slice of the graph.

slurp index . --smart
# → Detected 1 changed file (git diff)
# ✓ Updated 47 nodes · 46 edges in 0.1s
#   Full index would take: ~2.2s (21× faster)

The resulting graph is identical to a full index — nodes from re-parsed files are replaced, nodes from deleted files are dropped, and no dangling edges are left behind.

--dry-run lists the files it would touch and exits without writing:

slurp index . --smart --dry-run

It falls back to a full index, with a message, when there is no git repository or no existing graph to update. Speedup depends on what you touched: editing a leaf module is near-instant, while editing something the whole project imports pulls in most of it.

Supported languages

Language Parser
Python stdlib ast
TypeScript / JavaScript tree-sitter
Java tree-sitter
Rust tree-sitter
C# tree-sitter
Ruby tree-sitter
PHP tree-sitter
Kotlin tree-sitter ⚠️
Scala tree-sitter
Swift tree-sitter
C tree-sitter
C++ tree-sitter
Go regex
Lua regex
Elixir regex
PowerShell regex

⚠️ Kotlin: the tree-sitter-kotlin grammar has known parsing issues — it fails on a class with a body followed by an object declaration, which is ordinary Kotlin. Slurp detects the broken parse tree and the regex fallback is active in practice. The extra is still declared so a fixed grammar release takes effect without a code change.

Every tree-sitter language falls back to a regex parser when its grammar is not installed. The fallback extracts strictly less — it cannot nest inner classes or reach into method bodies — so slurp index always prints which parser it used:

✓ 312 nodes · 487 edges · 41 files
  Parsers: Python (ast) · Java (tree-sitter) · Ruby (regex fallback)
  Install the 'ts' extra for full TypeScript support: uv sync --extra ts

Python needs no extra (it uses the standard library). Go, Lua, Elixir and PowerShell are indexed by regex as their primary parser — no grammar is wired up for them, so their regex parser is the design rather than a degradation and is never reported as a fallback.

Optional extras

Extra Languages Install
ts TypeScript, JavaScript uv sync --extra ts
java Java uv sync --extra java
rust Rust uv sync --extra rust
csharp C# uv sync --extra csharp
ruby Ruby uv sync --extra ruby
php PHP uv sync --extra php
kotlin Kotlin uv sync --extra kotlin
scala Scala uv sync --extra scala
swift Swift uv sync --extra swift
cpp C, C++ uv sync --extra cpp
all-languages All of the above uv sync --extra all-languages

Each language records what matters for navigating that ecosystem: Java and C# annotations/attributes (@Service, [HttpGet]) plus access modifiers, Rust lifetimes and pub visibility, Ruby class methods and accessors, PHP magic methods (__get, __call), Kotlin data/sealed/suspend and extension receivers, Scala case classes and implicit, Swift computed properties and async. Relationships become typed edges — extends, implements (including Rust's impl Trait for Type), with (Scala), conforms_to (Swift), and mixin for Ruby's include/extend/prepend and PHP's trait use, Elixir's use/import/alias/require, and PowerShell's requires.

Broken-grammar guard. A tree-sitter grammar that returns a parse tree containing ERROR nodes silently drops whole declarations. Slurp checks for that after every parse and treats it as a parser failure: it warns on stderr and falls back to regex, which extracts less per declaration but does not lose most of the file.

After indexing, the full query pipeline works as usual:

slurp "auth flow" --graph graphify-out/graph.json --budget 4000

Works with graphify

Slurp is the query layer for graphify. Run graphify on your codebase, point slurp at the output.

graphify .                                        # generates graphify-out/graph.json
slurp "auth flow" --budget 4000                   # auto-discovers graphify-out/graph.json

Supported node fields:

{
  "id": "authenticate_user",
  "label": "authenticate_user",
  "type": "function",
  "description": "Validates credentials and returns JWT.",
  "importance": 9,
  "source_file": "src/auth/service.py",
  "source_location": "L42"
}

The type, description, importance, source_file, and source_location fields are optional but improve scoring and enable --inject-code. Any graph with id + label on nodes and source/target on edges will work.

Both links (graphify/NetworkX serialization) and edges are supported. Additional formats are auto-detected by extension:

Extension Format
.json graphify or generic JSON
.graphml GraphML (NetworkX / yEd / Gephi)
.csv Neo4j export (nodes CSV + sibling relationships CSV)

Use slurp convert or the convert_graph() API to export between formats.


MCP Integration

Run slurp as an MCP server so Claude Code (or any MCP-compatible agent) can query the graph directly.

.mcp.json — for global installs (uv tool install, pipx, pip):

{
  "mcpServers": {
    "slurp": {
      "command": "slurp",
      "args": ["serve", "--graph", "/absolute/path/to/graphify-out/graph.json"]
    }
  }
}

.mcp.json — if you installed with uv add inside a Python project:

{
  "mcpServers": {
    "slurp": {
      "command": "uv",
      "args": ["run", "slurp", "serve", "--graph", "graphify-out/graph.json"]
    }
  }
}

Windows: Use forward slashes or escaped backslashes in the graph path: "C:/Users/you/project/graphify-out/graph.json". If slurp isn't found, replace "command": "slurp" with the full path — find it with where slurp (CMD) or Get-Command slurp | Select-Object Source (PowerShell).

Tool exposed: slurp_query(query: str, budget: int = 4000) → str

Claude Code calls this automatically when it needs codebase context. The server runs over stdio and returns the formatted markdown subgraph — no HTTP, no ports.


.slurpignore

Exclude nodes by type, file path, or ID pattern. Create .slurpignore in your project root:

# Exclude documentation nodes
type:document
type:markdown

# Exclude test files
file:tests/**
file:**/*.test.ts

# Exclude generated code
id:generated_*

Pass a custom path with --ignore-file path/to/.slurpignore.


Design decisions

Power-iteration PageRank without numpy. nx.pagerank() requires numpy. Slurp implements a 20-line pure-Python power-iteration algorithm (convergence: Σ|rank_new − rank_old| < N × tol). Same result, no heavy dependency.

TF-IDF without scikit-learn. Hand-rolled TF-IDF with smoothed IDF (log((N+1)/(df+1)) + 1) and cosine similarity. The tokenizer splits camelCase and snake_case, so authenticate_user scores on both authenticate and user. The score_nodes() interface is backend-agnostic — swap to real embeddings with --backend openai or --backend anthropic without touching any caller.

YAML serializer without PyYAML. _yaml_scalar() renders Python primitives as valid YAML scalars using json.dumps() for strings that need quoting (JSON string literals are valid YAML 1.1). No PyYAML dependency.

lru_cache on the tiktoken encoder. tiktoken.get_encoding() reads tokenizer data from disk on first call. Caching with lru_cache(maxsize=8) means repeated token-counting calls within a single run hit memory, not disk.

+0.3 score boost for file_type == "code" nodes (clamped to 1.0). Documentation nodes compete unfairly with code in technical queries. The boost is bounded so it cannot override a genuinely high structural+semantic score.

--inject-code capped at 30 nodes. Code blocks are 50–200 tokens each. At 30 nodes, that's up to 6,000 extra tokens — manageable. At 200 nodes it would explode the context budget. The cap is enforced in both the CLI (warning message) and inject_code() (hard guard), so the formatter never receives oversized input.


Roadmap

  • v0.1.0loader, scorer, budget, formatter, audit — core pipeline, full tests, slurp QUERY + slurp stats
  • v0.2.0--explain, .slurpignore, --viz interactive HTML, --min-score, camelCase/snake_case tokenizer, --neighbor-decay
  • v0.3.0slurp serve (MCP stdio), slurp diff, slurp export (claude/chatgpt/claudemd), PyPI publish as slurp-graph
  • v0.4.0--backend openai|anthropic (optional embeddings), slurp benchmark, GraphML + Neo4j CSV loader, convert_graph()
  • v0.5.0--inject-code: extract real function bodies from source files and embed them in the context output
  • v0.6.0slurp index .: standalone static indexer (Python ast, TypeScript/JS, Go) — graphify is now optional

License

MIT © Juan Carlos Vallejo Ruiz

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

slurp_graph-0.9.1.tar.gz (136.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

slurp_graph-0.9.1-py3-none-any.whl (119.7 kB view details)

Uploaded Python 3

File details

Details for the file slurp_graph-0.9.1.tar.gz.

File metadata

  • Download URL: slurp_graph-0.9.1.tar.gz
  • Upload date:
  • Size: 136.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for slurp_graph-0.9.1.tar.gz
Algorithm Hash digest
SHA256 7582d48e74c02ca1786ff5714202d4ab233595d16c9c0944d465af53c8a1eab6
MD5 75f17006c4fbddae85ae1688b0a418d2
BLAKE2b-256 ff5ef3bad975ce2ef896e7b266b9e2d22f9aafd5f8f648e58730b4eb23e75c4c

See more details on using hashes here.

File details

Details for the file slurp_graph-0.9.1-py3-none-any.whl.

File metadata

  • Download URL: slurp_graph-0.9.1-py3-none-any.whl
  • Upload date:
  • Size: 119.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for slurp_graph-0.9.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9d1a4d997ca2c0b4257ee951b03dd0cd6468f5082d5299479dabe793fb78ac67
MD5 f4e6355c4224454ef2ef4464108f02a0
BLAKE2b-256 5ca35b526ceb1e9b2f6f55a49cb4b0a597886d1048612f27fde3d0a470b74015

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page