simeonbodurov 32bf8b4a37 feat(extract): add Pascal/Delphi and Lazarus IDE support (#781)
* feat(extract): add Pascal/Delphi language support

Adds full AST extraction for Pascal and Delphi source files using
tree-sitter-pascal (https://github.com/Isopod/tree-sitter-pascal).

Supported file extensions: .pas, .pp, .dpr, .dpk, .inc

Extracted nodes:
- File node (the .pas file itself)
- unit / program / library declarations
- class, interface, and helper type declarations
- procedure and function implementations

Extracted edges:
- file --contains--> module
- module --imports--> dependency (via uses clause, resolved to path-based IDs)
- class --inherits--> base class / interface
- class/module --contains/method--> procedure or function
- procedure --calls--> procedure (in-file call resolution)

Key design: uses clause targets are resolved to path-based node IDs by
scanning all Pascal files under the project root (_pascal_project_root +
_pascal_resolve_unit helpers). This avoids dangling import edges that
result from resolving bare unit names like "SysUtils" to IDs that never
match any file node.

Bare procedure calls (e.g. `Reset;` without parentheses) are detected
by inspecting statement nodes whose sole named child is an identifier,
in addition to the standard exprCall nodes used for calls with arguments.

Requires: pip install tree-sitter-pascal
(https://github.com/Isopod/tree-sitter-pascal)
If not installed, extract_pascal returns {"nodes":[], "edges":[], "error": ...}
so the rest of the pipeline is unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(extract): add Lazarus .lfm and .lpk file support

Adds two new extractors for Lazarus IDE-specific file formats:

extract_lazarus_form() — .lfm (Lazarus Form files)
  .lfm files are text-based UI component trees. The extractor parses
  `object Name: TClassName ... end` blocks to build a containment graph
  of form components, and captures `OnXxx = HandlerName` event bindings
  as `references` edges (context: "event") linking each component to
  its handler procedure.

extract_lazarus_package() — .lpk (Lazarus Package files)
  .lpk files are XML package definitions. The extractor reads the
  package name, required package dependencies (→ imports edges), and
  listed unit files (→ contains edges). Unit names are resolved to
  path-based node IDs via _pascal_resolve_unit so they connect to the
  same nodes produced by extract_pascal on .pas files.

Both extensions added to CODE_EXTENSIONS in detect.py and to _DISPATCH.
13 new tests in test_pascal.py cover both extractors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(pascal): fix dangling inherits-edge targets and capture all base classes

The declType/typeref handler built inherits edge targets with
_make_id(_read(child)) — just the bare class name. But class nodes
use _make_id(stem, type_name), so targets never matched, making the
entire class hierarchy invisible in the graph.

Add _pascal_class_stem_cache and _pascal_resolve_class(): strips the
conventional T/I prefix, locates the defining file by stem lookup
(same cache mechanism as _pascal_resolve_unit), and returns the
correct _make_id(file_stem, class_name) ID. RTL/unresolvable bases
(e.g. TObject) fall back to _make_id(bare_name) with an explicit
stub node, following the same pattern as the Python extractor.

Also remove the `break` that stopped after the first typeref, so
all parents are captured (e.g. class(TBase, IInterface)).

Extend test_pascal_no_dangling_edges to also assert that within-file
edge targets (contains, method, inherits, calls) resolve to real nodes.

* feat(extract): add Delphi .dfm form file support

Adds extract_delphi_form() for Delphi Form files (.dfm), which use the
same `object Name: TClassName ... end` text syntax as Lazarus .lfm files.

Binary .dfm files (FF 0A magic header) are skipped gracefully with an
informative error message so the pipeline is unaffected.  Text .dfm files
are parsed identically to .lfm: component containment (`contains` edges)
and event handler references (`references`, context "event").

Adds .dfm to _DISPATCH and CODE_EXTENSIONS.
10 new tests in test_pascal.py, including a regression test for the
binary-format detection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add .lpr extension and fix removesuffix in Pascal extractor

Address review feedback from @safishamsi:
- Add .lpr (Lazarus program file, identical syntax to .dpr) to _DISPATCH
  in extract.py and CODE_EXTENSIONS in detect.py so Lazarus project entry
  points are indexed. Completes the promised Lazarus IDE support.
- Replace rstrip("()") with removesuffix("()") in the call-resolution
  dict comprehension for precise suffix removal (rstrip strips individual
  characters, not the literal string "()").
- Add .lpr assertions to test_pascal_dispatch_registered and
  test_pascal_detect_extensions_registered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Simeon Bodurov <simeon.bodurov@speedy.bg>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 14:44:58 +01:00
2026-05-09 13:10:42 +01:00
2026-05-09 13:10:42 +01:00

Graphify

🇺🇸 English | 🇨🇳 简体中文 | 🇯🇵 日本語 | 🇰🇷 한국어 | 🇩🇪 Deutsch | 🇫🇷 Français | 🇪🇸 Español | 🇮🇳 हिन्दी | 🇧🇷 Português | 🇷🇺 Русский | 🇸🇦 العربية | 🇮🇹 Italiano | 🇵🇱 Polski | 🇳🇱 Nederlands | 🇹🇷 Türkçe | 🇺🇦 Українська | 🇻🇳 Tiếng Việt | 🇮🇩 Bahasa Indonesia | 🇸🇪 Svenska | 🇬🇷 Ελληνικά | 🇷🇴 Română | 🇨🇿 Čeština | 🇫🇮 Suomi | 🇩🇰 Dansk | 🇳🇴 Norsk | 🇭🇺 Magyar | 🇹🇭 ภาษาไทย | 🇹🇼 繁體中文

The Memory Layer CI PyPI Downloads Sponsor LinkedIn X

Star History Chart

Type /graphify in your AI coding assistant and it maps your entire project — code, docs, PDFs, images, videos — into a knowledge graph you can query instead of grepping through files.

Works in Claude Code, Codex, OpenCode, Cursor, Gemini CLI, GitHub Copilot CLI, VS Code Copilot Chat, Aider, OpenClaw, Factory Droid, Trae, Hermes, Kimi Code, Kiro, Pi, and Google Antigravity.

/graphify .

That's it. You get three files:

graphify-out/
├── graph.html       open in any browser — click nodes, filter, search
├── GRAPH_REPORT.md  the highlights: key concepts, surprising connections, suggested questions
└── graph.json       the full graph — query it anytime without re-reading your files

Install

Requires Python 3.10+

uv tool install graphifyy && graphify install
# or: pipx install graphifyy && graphify install
# or: pip install graphifyy && graphify install

Official package: The PyPI package is graphifyy (double-y). Other graphify* packages on PyPI are not affiliated. The CLI command is still graphify.

PowerShell note: Use graphify . not /graphify . — the leading slash is a path separator in PowerShell and will cause a "not recognized" error.

graphify: command not found? Use uv tool install graphifyy or pipx install graphifyy — both put the CLI on PATH automatically. With plain pip, add ~/.local/bin (Linux) or ~/Library/Python/3.x/bin (Mac) to your PATH, or run python -m graphify.

Pick your platform

Platform Install command
Claude Code (Linux/Mac) graphify install
Claude Code (Windows) graphify install --platform windows
Codex graphify install --platform codex
OpenCode graphify install --platform opencode
GitHub Copilot CLI graphify install --platform copilot
VS Code Copilot Chat graphify vscode install
Aider graphify install --platform aider
OpenClaw graphify install --platform claw
Factory Droid graphify install --platform droid
Trae graphify install --platform trae
Trae CN graphify install --platform trae-cn
Gemini CLI graphify install --platform gemini
Hermes graphify install --platform hermes
Kimi Code graphify install --platform kimi
Kiro IDE/CLI graphify kiro install
Pi coding agent graphify install --platform pi
Cursor graphify cursor install
Google Antigravity graphify antigravity install

Codex users: also add multi_agent = true under [features] in ~/.codex/config.toml. Codex uses $graphify instead of /graphify.


Make your assistant always use the graph

Run this once in your project after building a graph:

Platform Command
Claude Code graphify claude install
Codex graphify codex install
OpenCode graphify opencode install
GitHub Copilot CLI graphify copilot install
VS Code Copilot Chat graphify vscode install
Aider graphify aider install
OpenClaw graphify claw install
Factory Droid graphify droid install
Trae graphify trae install
Trae CN graphify trae-cn install
Cursor graphify cursor install
Gemini CLI graphify gemini install
Hermes graphify hermes install
Kimi Code graphify install --platform kimi
Kiro IDE/CLI graphify kiro install
Pi coding agent graphify pi install
Google Antigravity graphify antigravity install

This writes a small config file that tells your assistant to read GRAPH_REPORT.md before answering questions about your codebase. On platforms that support hooks (Claude Code, Codex, Gemini CLI), a hook fires automatically before every file-read call — your assistant navigates by the graph instead of grepping through everything.

To remove graphify from all platforms at once: graphify uninstall (add --purge to also delete graphify-out/). Or use the per-platform command (e.g. graphify claude uninstall).


What's in the report

  • God nodes — the most-connected concepts in your project. Everything flows through these.
  • Surprising connections — links between things that live in different files or modules. Ranked by how unexpected they are.
  • The "why" — inline comments (# NOTE:, # WHY:, # HACK:), docstrings, and design rationale from docs are extracted as separate nodes linked to the code they explain.
  • Suggested questions — 45 questions the graph is uniquely positioned to answer.
  • Confidence tags — every inferred relationship is marked EXTRACTED, INFERRED, or AMBIGUOUS. You always know what was found vs guessed.

What files it handles

Type Extensions
Code (28 languages) .py .ts .js .jsx .tsx .go .rs .java .c .cpp .rb .cs .kt .scala .php .swift .lua .luau .zig .ps1 .ex .exs .m .jl .vue .svelte .groovy .gradle .sql .f .F .f90 .F90 .f95 .F95 .f03 .F03 .f08 .F08
Docs .md .mdx .qmd .html .txt .rst .yaml .yml
Office .docx .xlsx (requires pip install graphifyy[office])
Google Workspace .gdoc .gsheet .gslides (opt-in; requires gws auth and --google-workspace; Sheets need pip install graphifyy[google])
PDFs .pdf
Images .png .jpg .webp .gif
Video / Audio .mp4 .mov .mp3 .wav and more (requires pip install graphifyy[video])
YouTube / URLs any video URL (requires pip install graphifyy[video])

Code is extracted locally with no API calls (AST via tree-sitter). Everything else goes through your AI assistant's model API.

Google Drive for desktop .gdoc, .gsheet, and .gslides files are shortcut pointers, not document content. To include native Google Docs, Sheets, and Slides in a headless extraction, install and authenticate the gws CLI, then run:

pip install "graphifyy[google]"  # needed for Google Sheets table rendering
gws auth login -s drive
graphify extract ./docs --google-workspace

You can also set GRAPHIFY_GOOGLE_WORKSPACE=1. Graphify exports shortcuts into graphify-out/converted/ as Markdown sidecars, then extracts those files.


Common commands

/graphify .                        # build graph for current folder
/graphify ./docs --update          # re-extract only changed files
/graphify . --cluster-only         # rerun clustering without re-extracting
/graphify . --no-viz               # skip the HTML, just the report + JSON
/graphify . --wiki                 # build a markdown wiki from the graph

/graphify query "what connects auth to the database?"
/graphify path "UserService" "DatabasePool"
/graphify explain "RateLimiter"

/graphify add https://arxiv.org/abs/1706.03762   # fetch a paper and add it
/graphify add <youtube-url>                       # transcribe and add a video

graphify hook install              # auto-rebuild on git commit
graphify merge-graphs a.json b.json              # combine two graphs

See the full command reference below.


Ignoring files

Create a .graphifyignore in your project root — same syntax as .gitignore, including ! negation:

# .graphifyignore
node_modules/
dist/
*.generated.py

# only index src/, ignore everything else
*
!src/
!src/**

Team setup

graphify-out/ is meant to be committed to git so everyone on the team starts with a map.

Recommended .gitignore additions:

graphify-out/manifest.json    # mtime-based, breaks after git clone
graphify-out/cost.json        # local only
# graphify-out/cache/         # optional: commit for speed, skip to keep repo small

Workflow:

  1. One person runs /graphify . and commits graphify-out/.
  2. Everyone pulls — their assistant reads the graph immediately.
  3. Run graphify hook install to auto-rebuild after each commit (AST only, no API cost). This also sets up a git merge driver so graph.json is never left with conflict markers — two devs committing in parallel get their graphs union-merged automatically.
  4. When docs or papers change, run /graphify --update to refresh those nodes.

Using the graph directly

# query the graph from the terminal
graphify query "show the auth flow"
graphify query "what connects DigestAuth to Response?" --graph graphify-out/graph.json

# expose the graph as an MCP server (for repeated tool-call access)
python -m graphify.serve graphify-out/graph.json

# register with Kimi Code:
kimi mcp add --transport stdio graphify -- python -m graphify.serve graphify-out/graph.json

The MCP server gives your assistant structured access: query_graph, get_node, get_neighbors, shortest_path.

WSL / Linux note: Ubuntu ships python3, not python. Use a venv to avoid conflicts:

python3 -m venv .venv && .venv/bin/pip install "graphifyy[mcp]"

Privacy

  • Code files — processed locally via tree-sitter. Nothing leaves your machine.
  • Video / audio — transcribed locally with faster-whisper. Nothing leaves your machine.
  • Docs, PDFs, images — sent to your AI assistant for semantic extraction (via the /graphify skill, using whatever model your IDE session runs). Headless graphify extract requires GEMINI_API_KEY / GOOGLE_API_KEY (Gemini), MOONSHOT_API_KEY (Kimi), ANTHROPIC_API_KEY (Claude), OPENAI_API_KEY (OpenAI), a running Ollama instance (OLLAMA_BASE_URL), or AWS credentials via the standard provider chain (Bedrock - no API key needed, uses IAM). The --dedup-llm flag uses the same key.
  • No telemetry, no usage tracking, no analytics.

Full command reference

/graphify                          # run on current directory
/graphify ./raw                    # run on a specific folder
/graphify ./raw --mode deep        # more aggressive relationship extraction
/graphify ./raw --update           # re-extract only changed files
/graphify ./raw --directed         # preserve edge direction
/graphify ./raw --cluster-only     # rerun clustering on existing graph
/graphify ./raw --no-viz           # skip HTML visualization
/graphify ./raw --obsidian         # generate Obsidian vault
/graphify ./raw --wiki             # build agent-crawlable markdown wiki
/graphify ./raw --svg              # export graph.svg
/graphify ./raw --graphml          # export for Gephi / yEd
/graphify ./raw --neo4j            # generate cypher.txt for Neo4j
/graphify ./raw --neo4j-push bolt://localhost:7687
/graphify ./raw --watch            # auto-sync as files change
/graphify ./raw --mcp              # start MCP stdio server

/graphify add https://arxiv.org/abs/1706.03762
/graphify add <video-url>
/graphify add https://... --author "Name" --contributor "Name"

/graphify query "what connects attention to the optimizer?"
/graphify query "..." --dfs --budget 1500
/graphify path "DigestAuth" "Response"
/graphify explain "SwinTransformer"

graphify uninstall                 # remove from all platforms in one shot
graphify uninstall --purge         # also delete graphify-out/

graphify hook install              # post-commit + post-checkout hooks
graphify hook uninstall
graphify hook status

graphify claude install / uninstall
graphify codex install / uninstall
graphify opencode install
graphify cursor install / uninstall
graphify gemini install / uninstall
graphify copilot install / uninstall
graphify aider install / uninstall
graphify claw install / uninstall
graphify droid install / uninstall
graphify trae install / uninstall
graphify trae-cn install / uninstall
graphify hermes install / uninstall
graphify kiro install / uninstall
graphify antigravity install / uninstall

graphify extract ./docs                        # headless LLM extraction for CI (no IDE needed)
graphify extract ./docs --backend gemini       # explicit backend: gemini, kimi, claude, openai, ollama, or bedrock
graphify extract ./docs --backend gemini --model gemini-3.1-pro-preview
graphify extract ./docs --backend ollama       # local Ollama (set OLLAMA_BASE_URL / OLLAMA_MODEL)
graphify extract ./docs --backend bedrock      # AWS Bedrock via IAM - no API key, uses AWS credential chain
graphify extract ./docs --google-workspace     # export .gdoc/.gsheet/.gslides via gws before extraction
graphify extract ./docs --no-cluster           # raw extraction only, skip clustering
graphify extract ./docs --dedup-llm            # LLM tiebreaker for ambiguous entity pairs (uses same API key)
graphify extract ./docs --global --as myrepo   # extract and register into the cross-project global graph
GRAPHIFY_MAX_OUTPUT_TOKENS=32768 graphify extract ./docs --backend claude  # raise output cap for dense corpora

graphify global add graphify-out/graph.json myrepo   # register a project graph into ~/.graphify/global.json
graphify global remove myrepo                         # remove a project from the global graph
graphify global list                                  # show all registered repos + node/edge counts
graphify global path                                  # print path to the global graph file

graphify clone https://github.com/karpathy/nanoGPT
graphify merge-graphs a.json b.json --out merged.json
graphify watch ./src
graphify check-update ./src
graphify update ./src
graphify cluster-only ./my-project
graphify cluster-only ./my-project --graph path/to/graph.json  # custom graph location

Learn more


Built on graphify — Penpax

Penpax is the always-on layer built on top of graphify — it applies the same graph approach to your entire working life: meetings, browser history, emails, files, and code, updating continuously in the background.

Built for people whose work lives across hundreds of conversations and documents they can never fully reconstruct. No cloud, fully on-device.

Free trial launching soon. Join the waitlist →


Contributing

Worked examples are the most useful contribution. Run /graphify on a real corpus, save the output to worked/{slug}/, write an honest review.md covering what the graph got right and wrong, and open a PR.

Extraction bugs — open an issue with the input file, the cache entry (graphify-out/cache/), and what was missed or wrong.

See ARCHITECTURE.md for module responsibilities and how to add a language.

Languages
Python 100%