Vis
Back to extensions

blockether/vis-graphify

Code knowledge graphs for Vis with graphify: build, search, explain, paths, hubs, change impact, exact references, safe renames and moves of definitions and files, and domain flows.

  • graph
  • code

Install

Only approved releases are listed. Each version keeps its reviewed commit. You are viewing a different version from the catalog default.

Approved releases (23)
  1. 0.15.3Oct 24, 20260a0f94a8bcdaRelease notes
  2. 0.13.0Oct 24, 202638868e6309c2Release notes
  3. 0.8.1Oct 23, 202642138d696004Release notes
  4. 0.7.0Oct 23, 2026929a55e0e1abRelease notes
  5. 0.5.4Oct 22, 2026167cad7aa0a8Release notes
  6. 0.5.3Oct 22, 2026c52df2c4cde9Release notes
  7. 0.5.2Oct 22, 202655a20b9c0221Release notes
  8. 0.5.1Oct 22, 20269b7d0db32074Release notes
  9. 0.5.0Oct 22, 2026fcd448a572acRelease notes
  10. 0.4.1Oct 22, 2026097ee3137cb2Release notes
  11. 0.4.0Oct 22, 2026dcd171e565e9Release notes
  12. 0.3.3Oct 22, 20268f0b248f1e1eRelease notes
  13. 0.3.2Oct 22, 202672df2b6f3000Release notes
  14. 0.3.1Oct 22, 2026e472b045a933Release notes
  15. 0.3.0Oct 22, 2026a8c87e0737f7Release notes
  16. 0.2.5Oct 22, 20266222939924c3Release notes
  17. 0.2.4Oct 22, 2026697886c6a0fbRelease notes
  18. 0.2.3Oct 22, 20265cf17b022f0eRelease notes
  19. 0.2.2Oct 14, 2026dcff80cc1017Release notes
  20. 0.2.1Oct 10, 20268589fb741156Release notes
  21. 0.2.0Oct 10, 202657a736494f07Release notes
  22. 0.1.1Oct 10, 2026ada92a67c207Release notes
  23. 0.1.0Oct 10, 2026e55784db3423Release notes

This command selects version 0.7.0 at its approved commit. It never follows a moving tag or branch.

Project: run from your project directory to install in .vis/extensions. This command does not add an extensions entry to vis.yml. Add --save to also record the installation. Save an installation in configuration to share the setup.

Review the source first. --trust allows extension code and build backends to run with your permissions.

vis-agent extension install \
  'blockether/vis-graphify' \
  --version '0.7.0' \
  --project \
  --trust

Then start Vis or use /reload. Dependencies are prepared automatically.

Already installed? Check, update or roll back
vis-agent extension versions 'blockether/vis-graphify'
vis-agent extension update 'blockether/vis-graphify' --trust
vis-agent extension rollback 'blockether/vis-graphify' --trust

Use the identifier shown above, not the Python package name. Add --project for a project installation. Update selects the latest approved stable version; rollback restores the previous pinned source. Choose a specific version and read the lifecycle contract.

Project details

Version
0.7.0
Extension
blockether/vis-graphify
Project folder
Repository root
License
Apache-2.0
GitHub stars
0
Downloads
3
Updated
Oct 23, 2026
GitHub owner
Blockether
Reviewed commit
929a55e0e1ab
Metadata checked
Oct 23, 2026

Dependencies

Python >=3.12

  • vis-agent>=0.2.45
  • graphifyy @ git+https://github.com/Blockether/graphify@v0.9.93-blockether.10
  • graspologic-native>=1.3.1,<2

README

vis-graphify

Code knowledge graphs for Vis, built with the Blockether fork of graphify. The fork adds full Clojure support over Blockether/tree-sitter-clojure: namespaces, vars, :require aliases, cross-file calls, protocols, records and Clojure 1.12/1.13 syntax.

When to use

  • You want to know who calls a function, across files: use graphify.explain.
  • You plan a change and want to see what it can break: use graphify.affected.
  • You want to rename a function, method, class or Clojure var everywhere without touching locals, fields, strings or other symbols with the same name: use graphify.rename. See Rename a symbol.
  • You want to add a parameter to a function and pass a value at every call: use graphify.add_parameter. See Add a parameter.
  • You want to move a function or a type to another file, or move a file to a new module or namespace, and fix every import: use graphify.move or graphify.move_file. See Move code.
  • You want to see how two parts of the code connect: use graphify.shortest_path.
  • You join an unknown codebase and want its central code first: use graphify.hubs.
  • You want to see how commands, queries and events flow between your services, or find calls to commands that no service registers: use graphify.domain. See Domain flows.

The graph comes from tree-sitter syntax trees. A build makes no LLM call and sends no code anywhere.

Install

vis-agent extension install Blockether/vis-graphify --trust

Vis prepares a private environment with graphify and the Clojure grammar. Run /reload in a session.

Use

In a Vis session, ask for the graph work in chat, for example "who calls run-tests in this project?". The agent uses these tools in its Python sandbox:

Call Result
graphify.build(root=".") Creates or updates <root>/graphify-out/graph.json. Other calls do this for you when the graph is missing or a source file changed.
graphify.status(root=".") Node, edge and file counts, and the build time.
graphify.search("gateway.*client") Nodes whose label, id or file matches the regex.
graphify.explain("my.ns/run") The node, what it calls and what calls or contains it.
graphify.shortest_path("a", "b") The shortest chain of edges between two nodes.
graphify.hubs(limit=20) The most called nodes.
graphify.affected("my.ns/run", within="src/api/") Every caller, importer and user, across all steps, with distance and file. within keeps only one folder or glob. depth=2 stops after two steps.
graphify.references("my.ns/run") Every exact site of a symbol: file, line, column and role.
graphify.rename("my.ns/run", "start", apply=True) Renames the symbol everywhere and updates the graph. Without apply, it only returns the diff.
graphify.add_parameter("Total", "currency string", '"EUR"', apply=True) Adds a last parameter to the definition and the argument to every call. Without apply, it only returns the diff.
graphify.move("my.ns/run", "src/my/runner.clj", apply=True) Moves one top-level definition to another file, also a new one. Every use, import and require follows.
graphify.move_file("src/my/ns.clj", "src/my/core.clj", apply=True) Moves a file and renames its module or namespace at every use. For Clojure, the test namespace moves too.
graphify.domain(root=".") The domain model: services, commands, queries, events, links, schemas and findings. Writes DOMAIN.md.

You can name a node by its id, its label (run()), its bare name (run) or a qualified name (my.ns/run, orders.Order, Ledger.post or crate::util::sum), or by its file and name (src/util.rs::checksum). If a name matches more than one node, the error lists each candidate id with its file and line.

print(result) shows a short summary with file:line locations. Read a field, such as diff, for the details. The graph build writes graphify-out/.gitignore, so git and grep skip the graph files.

Rename a symbol

Ask in chat, for example "rename parse_config to load_config". The agent calls graphify.rename("parse_config()", "load_config", apply=True). When the rename has a conflict, the call writes nothing. The result has these fields:

  • diff: the change in each file;
  • conflicts: why the rename is unsafe, if it is. Examples are a file that already uses the new name, a method that overrides a base class or implements a trait, or a common method name such as get on receivers of unknown type;
  • mentions: other code symbols that spell the old name. They stay unchanged; check them.
  • text_mentions: the count of strings, comments and keywords that spell the old name. They stay unchanged.

Without apply=True, the call is a preview and writes nothing. A file that changed after the plan stops the write.

The rename works in every language with a tree-sitter grammar in graphify: Python, JavaScript, TypeScript, Go, Rust, Java, C#, Kotlin, Ruby, PHP, Clojure and more. It follows imports, aliases, re-exports and declared receiver types, and it skips parameters, locals and fields with the same name. For Clojure, it follows :as, :refer, :refer :all and :rename, and changes declare, defmethod, protocol implementations, #'var, resolve, syntax-quote and ->Rec factories. graphify.references() lists the same sites without a change.

Add a parameter

Ask in chat, for example "add a currency string parameter to pricing.Total and pass "EUR"". The agent calls graphify.add_parameter("pricing/pricing.go::Total", "currency string", '"EUR"', apply=True). The call finds the calls with the same exact resolution as graphify.references(). A method or a function in another package with the same name stays unchanged.

  • Write the parameter as the language writes it: currency string (Go), currency: str (Python), currency: string (TypeScript) or currency (Clojure).
  • The parameter goes last in the definition, and the argument goes last in each call.
  • A multi-line call with a trailing comma gets the argument on its own line.

The call writes nothing when a site blocks the change. Examples are a function that is passed as a value, not called, or a Python list that ends with *args, **kwargs or a default. In Python, pass name=value after a default. Then change the blocked sites by hand.

Move code

Ask in chat, for example "move slugify from app.util to a new file app/text.py". The agent calls graphify.move("app/util.py::slugify", "app/text.py", apply=True). To move a whole file, the agent calls graphify.move_file("src/app/util.clj", "src/app/text/core.clj", apply=True).

  • The move works for Clojure, Python, JavaScript, TypeScript, Go and Rust. It also works for Java, Kotlin, Scala, Groovy, C#, VB.NET, PHP, Swift, Elixir, Fortran, Erlang, OCaml, Pascal and Apex. The languages that load files by path work too: C, C++, Objective-C, Ruby, shell, PowerShell, Julia, Verilog, Lua, Zig, R, SQL, Common Lisp, Robot Framework, COBOL, Dart, Solidity, Terraform and others.
  • Every import, require, mod declaration and qualified use follows the code.
  • The moved definition takes the imports that it needs.
  • For Clojure, move_file changes the ns form. It also moves the test namespace x-test of namespace x. Give tests=False to keep the tests in place.
  • For Rust, impl blocks move with their type. A private item that the new module needs becomes pub(crate). notes lists these changes.

The result has diff, created, deleted, renames, notes and conflicts. The call writes nothing when a conflict blocks the move. Examples are a name that the target file already defines, a target file that exists, or an import cycle. Without apply=True, the call is a preview. A written move updates the graph and runs the project check, as rename does.

Domain flows

graphify.domain() reads the framework registrations of your Clojure services and connects them. The built-in edd-core plugin reads edd-core commands, queries, events, effects and Malli schemas. The call writes these files to <root>/graphify-out/domain/:

  • DOMAIN.md: a summary, findings, Mermaid flowcharts for the system and each service, a sequence diagram for each entry point, and the schemas;
  • domain.json: the full model;
  • schemas/: one JSON Schema for each Malli schema.

The result lists the findings, errors first. For example, missing-command means that code calls a command that the target service does not register. payload-invalid means that a call sends data that the full :consumes schema of its target rejects. Codes that start with schema- mark a broken Malli schema, such as an unknown type, :min above :max or a regex that cannot compile. DOMAIN.md lists these problems under each schema. graphify.build() also adds the domain elements to the graph, so graphify.explain("domain:command:orders-svc:place-order") shows the handler.

To read another framework, write a domain plugin: a Python file with a plugin object that has a name and an extract(corpus, model) method. The plugin guide describes the contract. Make the plugin available in one of these ways:

  • Put the file in <root>/.graphify/plugins/. graphify finds it for that project.
  • Pass its path or name in plugins, for example graphify.domain(plugins=["tools/jobs.py"]).
  • Add it to src/vis_graphify/domain_plugins/ in this repository. Every Vis user of the extension then gets it.

Development

uv sync
uvx ruff format --check . && uvx ruff check .
uv run --with pytest pytest tests -q

Benchmark

bench/ measures extraction, queries and change tracking on real Clojure projects against clj-kondo. On the Vis sources (235 files), definitions have a recall of 0.999, references a recall of 0.996, and explain() finds 99.8 percent of the callers in a few milliseconds. A full build takes about 4 s, and an update after a one-file change about 5 s.

License

Apache-2.0. graphify is MIT-licensed; see NOTICE.

Community feedback

Votes and display names are not verified identities. One vote per network address; shared networks share a vote. Select your current choice again to clear it.

Loading feedback…

Comments

Add a comment

Comments appear after moderation. Use a public display name, not private information. Five comments per network address in 24 hours.

BlocketherReview community code before installing.

1 of 2 · Repository

Add a repository

Share a public GitHub project with a published Release. We check its files and metadata before moderation. New releases are discovered after your repository is approved.

Folder containing pyproject.toml and extension.py. Leave empty if they are at the repository root.

Use v1.2.0 or a monorepo tag such as vis-greeting/v1.2.0. Its version must match the manifest. A Git tag alone is not a published Release.

Submissions stay private until approved. The owner is read from GitHub. A listing does not verify the submitter or audit the code.