callscape
Point it at a codebase, get a browsable static HTML call-graph map — functions, callers, class/struct definitions, all cross-linked. One output file, no server, no dependencies at view time. Built on tree-sitter, so each new language is one self-contained PR.
pip install callscape # or: pip install -e ".[dev]" from a checkout
callscape path/to/repo -o map.html
open map.html
callscape: 12 files · 55 definitions · 174 call edges (163 unresolved)
wrote map.html — open it in a browser
What you get
- Overview — stats, per-language file counts, most-connected symbols.
- Symbol pages — signature, source, callers, callees; every name is a link.
- Call-flow graph — callers → symbol → callees as a clickable SVG.
- Search — press
/, filter by symbol or file path. - Single file — the whole map is one self-contained
.html. Email it, attach it to a PR, drop it on any static host.
Languages today: Python, JavaScript, Go.
How it works
- Walk the repo, parse each supported file with its tree-sitter grammar.
- Each language adapter extracts definitions (functions, methods, classes, structs, interfaces) and call sites from the syntax tree.
- Calls are attributed to their smallest enclosing definition, then resolved by name across the whole repo.
- The index is embedded as JSON into a self-contained HTML viewer (vanilla JS, no CDN, no telemetry).
Honest limitations
Resolution is name-based, not type-based. obj.render() links to every
definition named render — dynamic dispatch is approximated, not solved.
Names matching more than 12 definitions are treated as too generic and listed
as unresolved instead of spraying edges. This is a map for orienting yourself
in an unfamiliar codebase, not a precision static analyzer.
Adding a language (the fun part)
One adapter = one PR. An adapter is a single module in callscape/languages/
(~100 lines) exposing four things:
NAME = "ruby"
EXTENSIONS = {".rb"}
def language() -> tree_sitter.Language:
return Language(tree_sitter_ruby.language())
def extract(root_node, source_bytes) -> tuple[list[RawDef], list[RawCall]]:
# walk the tree; return definitions (name, kind, byte span, line span,
# signature, parent) and call sites (bare callee name, byte, line)
...
Then:
- Add the grammar package (
tree-sitter-ruby) topyproject.tomldependencies. - List the module in
_ADAPTER_MODULESincallscape/languages/__init__.py. - Add a
test_ruby_defs_and_callscase intests/test_languages.py(see the existing Python/JS/Go cases — ~30 lines each).
Enclosure attribution, cross-file resolution, and the viewer are all
language-agnostic — the adapter never touches them. Use
callscape/languages/go.py as the template; it is the smallest.
CLI
callscape PATH [-o OUT.html] [--title TITLE] [--exclude GLOB]...
--exclude globs are relative to the root and repeatable. node_modules,
virtualenvs, vendor, build output, and hidden directories are skipped
automatically; files over 1.5 MB are ignored.
Development
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/pytest
.venv/bin/callscape . -o demo/self.html --title "callscape (self)" # dogfood
MIT license.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file callscape-0.3.0.tar.gz.
File metadata
- Download URL: callscape-0.3.0.tar.gz
- Upload date:
- Size: 20.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f21e93fc31185941c742d6c14705dc083429503156540ed72507631efab3a01a
|
|
| MD5 |
adb0af6bd7147fe34be76af043e8a5dc
|
|
| BLAKE2b-256 |
7bfa59dde6f6ad1ab401a54c02c24a0f698270d11c62e6ddf14319c346a044dd
|
Provenance
The following attestation bundles were made for callscape-0.3.0.tar.gz:
Publisher:
release.yml on sophie-nguyenthuthuy/callscape
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
callscape-0.3.0.tar.gz -
Subject digest:
f21e93fc31185941c742d6c14705dc083429503156540ed72507631efab3a01a - Sigstore transparency entry: 2388028786
- Sigstore integration time:
-
Permalink:
sophie-nguyenthuthuy/callscape@edb74c009817eba2de05c9f9e014e129dedc863b -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/sophie-nguyenthuthuy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@edb74c009817eba2de05c9f9e014e129dedc863b -
Trigger Event:
push
-
Statement type:
File details
Details for the file callscape-0.3.0-py3-none-any.whl.
File metadata
- Download URL: callscape-0.3.0-py3-none-any.whl
- Upload date:
- Size: 21.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4800e213e80559686a3625b10cea1e5fe2fc335be677354335d3bed8cbcc3ba
|
|
| MD5 |
d18c79a34470339f53af457dc312d472
|
|
| BLAKE2b-256 |
a427a9a396b8865ff5bb66f99a3e7a558ef6c810e2870fe1d41079bf6b01179a
|
Provenance
The following attestation bundles were made for callscape-0.3.0-py3-none-any.whl:
Publisher:
release.yml on sophie-nguyenthuthuy/callscape
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
callscape-0.3.0-py3-none-any.whl -
Subject digest:
f4800e213e80559686a3625b10cea1e5fe2fc335be677354335d3bed8cbcc3ba - Sigstore transparency entry: 2388028809
- Sigstore integration time:
-
Permalink:
sophie-nguyenthuthuy/callscape@edb74c009817eba2de05c9f9e014e129dedc863b -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/sophie-nguyenthuthuy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@edb74c009817eba2de05c9f9e014e129dedc863b -
Trigger Event:
push
-
Statement type: