Skip to main content

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.

callscape browsing its own source

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

  1. Walk the repo, parse each supported file with its tree-sitter grammar.
  2. Each language adapter extracts definitions (functions, methods, classes, structs, interfaces) and call sites from the syntax tree.
  3. Calls are attributed to their smallest enclosing definition, then resolved by name across the whole repo.
  4. 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:

  1. Add the grammar package (tree-sitter-ruby) to pyproject.toml dependencies.
  2. List the module in _ADAPTER_MODULES in callscape/languages/__init__.py.
  3. Add a test_ruby_defs_and_calls case in tests/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

callscape-0.3.0.tar.gz (20.8 kB view details)

Uploaded Source

Built Distribution

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

callscape-0.3.0-py3-none-any.whl (21.8 kB view details)

Uploaded Python 3

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

Hashes for callscape-0.3.0.tar.gz
Algorithm Hash digest
SHA256 f21e93fc31185941c742d6c14705dc083429503156540ed72507631efab3a01a
MD5 adb0af6bd7147fe34be76af043e8a5dc
BLAKE2b-256 7bfa59dde6f6ad1ab401a54c02c24a0f698270d11c62e6ddf14319c346a044dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for callscape-0.3.0.tar.gz:

Publisher: release.yml on sophie-nguyenthuthuy/callscape

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for callscape-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f4800e213e80559686a3625b10cea1e5fe2fc335be677354335d3bed8cbcc3ba
MD5 d18c79a34470339f53af457dc312d472
BLAKE2b-256 a427a9a396b8865ff5bb66f99a3e7a558ef6c810e2870fe1d41079bf6b01179a

See more details on using hashes here.

Provenance

The following attestation bundles were made for callscape-0.3.0-py3-none-any.whl:

Publisher: release.yml on sophie-nguyenthuthuy/callscape

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page