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.1.0.tar.gz (18.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.1.0-py3-none-any.whl (18.4 kB view details)

Uploaded Python 3

File details

Details for the file callscape-0.1.0.tar.gz.

File metadata

  • Download URL: callscape-0.1.0.tar.gz
  • Upload date:
  • Size: 18.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.1.0.tar.gz
Algorithm Hash digest
SHA256 8fca625f00266a57708c24ab746670d2ee0e359e547896aed4fa0c9a5a73c8fd
MD5 3a3e5567553c9f95c7d3d6672c02d3fe
BLAKE2b-256 6f90f965edeb425f4fdccc30709eae132718bbd4137836f10f532986c64aeb4a

See more details on using hashes here.

Provenance

The following attestation bundles were made for callscape-0.1.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.1.0-py3-none-any.whl.

File metadata

  • Download URL: callscape-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.4 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.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 33a9304f455878d02bf778b4a835c2bc2f9eeb15b9c98c5017200f3971b89305
MD5 13f7998b252643f76430acd388862e3d
BLAKE2b-256 1c376ff827df2af8d0adbb6c453df4f6a24768a4aea4b52b0c9b0fef59ce21e9

See more details on using hashes here.

Provenance

The following attestation bundles were made for callscape-0.1.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

0.3.0

2 files

0.2.0

2 files

This release

0.1.0 This release

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