npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rtsantos3/trellis-app

v0.16.0-beta.5f

Published

Knowledge graph framework for Jupyter notebooks — organize, link, and visualize data science workflows with a force-directed graph GUI, CLI, and REST API

Readme

Trellis — Knowledge Graph for Jupyter Notebooks

Organize, link, and visualize your data science work. Trellis turns a project directory into an interconnected knowledge graph — notebooks, datasets, findings, and concepts — with a force-directed graph GUI, tiled workspace, embedded JupyterLab, and a full CLI + REST API.

Think Obsidian meets Hex, built for data science and research workflows.

Latest: 0.16.0-beta.5f — current beta release.

How It Works

Trellis wraps your existing project directory — notebooks, scripts, datasets, and outputs — in a local SQLite-backed knowledge graph. You run trellis init to scaffold a .trellis/ metadata store, then use the CLI or GUI to register nodes (notebooks, datasets, findings, concepts, etc.) and link them with typed, weighted edges. A built-in FastAPI server exposes the graph over REST and launches a managed JupyterLab subprocess, so the browser-based GUI gives you a force-directed graph view, a tiled workspace, and an embedded notebook editor in one window. File watchers detect new artifacts as notebooks run, and a mutation log tracks every change with actor attribution — making Trellis suitable for both interactive use and agent-driven pipelines.


Features

Core (Python)

  • Knowledge graph — nodes (project, notebook, dataset, finding, concept, hypothesis, method, reference, artifact, custom) and typed edges (supports, contradicts, extends, depends_on, references, derived_from, parent_of, related_to, custom)
  • SQLite storage — local-first SQLAlchemy store with parent hierarchy, slug uniqueness, and subgraph traversal
  • CLItrellis init, add, link, annotate, annotation, list, get, find, grep, subgraph, path, history, export, import, update, rm/restore/purge, kernel register, serve
  • Dataset accesstrellis.load('slug') → pandas DataFrame; auto-discovers .csv/.parquet files from data/ directory
  • Artifact detection — file-watcher-based artifact capture with auto-linking to parent notebooks

API (FastAPI)

  • Full REST API for nodes, edges, annotations, search, graph traversal
  • Managed Jupyter Notebook 7 subprocess integration
  • Notebook content serving with allowlisted roots and size cap
  • Dataset discovery and artifact scan endpoints
  • API key authentication (TRELLIS_API_KEY) with reverse-proxy support (TRELLIS_TRUST_PROXY)

GUI (React + Vite)

  • Tiled workspace — draggable/resizable panels with persisted layout
  • Graph panel — force-directed knowledge graph with node type icons, edge labels, zoom/pan, search, and command palette
  • Detail panel — Details, History, Metadata, Git Timeline, and Artifacts tabs; git commit history with diff previews for file-backed nodes
  • Files panel — workspace file browser with system viewer integration
  • Notebook panel — embedded JupyterLab iframe per notebook node (.ipynb, .Rmd, .qmd, .py, .r, .sh, .md)
  • Force layout controls — gravity, repulsion, link distance, and halo radius sliders

Installation

Requirements

  • Node.js 18+
  • Python 3.10+ (auto-detected; used as the backend runtime)

Install

npm install -g @rtsantos3/trellis-app

The installer auto-detects your Python 3.10+ environment and bootstraps the Python backend on first run. If you use conda:

conda create -n trellis python=3.12
conda activate trellis
npm install -g @rtsantos3/trellis-app

To update Trellis, reinstall the package:

npm install -g @rtsantos3/trellis-app

The NPM latest dist-tag tracks the newest tagged Trellis release. The launcher re-syncs the bundled Python backend when the installed Python package version does not match the NPM package.


Quickstart

# initialize a project
trellis init

# optional: register a Jupyter kernel for notebook editing
python -m pip install ipykernel
python -m ipykernel install --user --name trellis --display-name "Python (trellis)"

# start the server
trellis serve

Then open http://127.0.0.1:8050 and select a node in the graph or tree to view details, annotations, history, and notebooks.


Running

# 1) Start backend + static frontend
trellis serve

# 2) Open UI
# http://127.0.0.1:8050

# Debug/reload mode
trellis serve --debug

# Disable managed JupyterLab startup
trellis serve --no-jupyter

# Custom JupyterLab preferred port
trellis serve --jupyter-port 8899

# Custom API/UI port
trellis serve --port 8080

# Non-loopback bind requires explicit opt-in
trellis serve --host 0.0.0.0 --insecure-expose

API Authentication

By default, Trellis runs on 127.0.0.1 (localhost) with no authentication required. If you need to expose Trellis over a network, set an API key:

# 1. Export your key (use any secure random string)
export TRELLIS_API_KEY="$(openssl rand -hex 32)"

# 2. Start with network binding
trellis serve --host 0.0.0.0 --insecure-expose

Clients authenticate with either header:

curl -H "Authorization: Bearer $TRELLIS_API_KEY" http://<host>:8050/api/graph
# or
curl -H "X-API-Key: $TRELLIS_API_KEY" http://<host>:8050/api/graph

If you're behind a reverse proxy, also set TRELLIS_TRUST_PROXY=true so auth is enforced regardless of the forwarded client address.

Environment variables

| Variable | Default | Description | |----------|---------|-------------| | TRELLIS_API_KEY | unset | API token; required when binding to non-loopback interfaces | | TRELLIS_TRUST_PROXY | false | Enforce auth behind a reverse proxy | | TRELLIS_CORS_ORIGINS | localhost origins | Comma-separated allowed browser origins | | TRELLIS_NOTEBOOK_ROOTS | cwd | Comma-separated allowlisted roots for notebook file access | | TRELLIS_NOTEBOOK_MAX_BYTES | 10485760 | Max notebook file size (10 MiB) |


Node Types

| Type | Description | |------|-------------| | project | Top-level container for a body of work | | notebook | A computational notebook or script (.ipynb, .Rmd, .qmd, .py, .r, .sh, .md) | | dataset | A data source — CSV, Parquet, database table, etc. | | finding | A discrete result or observation produced by analysis | | concept | A domain idea or theme that connects related work | | hypothesis | A testable claim under investigation | | method | An analytical technique or pipeline step | | reference | A canonical external source node; legacy paper and url inputs/records remain accepted as compatibility aliases, but new usage should prefer reference | | artifact | A generated output — plot, model file, export, etc. | | custom | A user-defined node type for cases that do not fit the built-in semantic classes |

Edge Types

| Type | Description | |------|-------------| | supports | Source provides evidence for target | | contradicts | Source provides evidence against target | | extends | Source builds on or refines target | | depends_on | Source requires target to function | | references | Source cites or links to target | | derived_from | Source was produced from target | | parent_of | Source is the hierarchical parent of target | | related_to | General association (weak-tier) | | custom | User-defined relationship type |


CLI

trellis init

# create/link/annotate
trellis add project "My project"
trellis add notebook "My notebook" --parent my-project --file analysis.ipynb --tags baseline,eda
trellis add dataset "My dataset" --parent my-project
trellis link my-notebook my-dataset references
trellis annotate my-notebook "Key finding: seasonal drift" --tags review

# inspect
trellis list
trellis list --include-deleted
trellis get my-notebook --json
trellis find --tag baseline --text drift --limit 20 --json
trellis grep "seasonal drift" --scope node --scope annotation --json
trellis subgraph my-project --mode edges --depth 2 --json
trellis subgraph my-project --mode edges --depth 2 --summary
trellis path my-notebook my-dataset --summary
trellis info my-notebook
trellis show

# update (partial patch; only provided fields are changed)
trellis update my-notebook --title "My notebook v2" --tags baseline,production
trellis update my-notebook --attribute description --text "Updated summary"
trellis add reference "Turney 2010" --parent my-project --metadata '{"schema":"reference-v1","title":"Turney 2010","doi":"10.1000/example"}'
trellis update turney-2010 --citation "Turney, 2010" --metadata '{"url":"https://example.com/paper"}'
trellis update --uuid <node-uuid> --clear-description --clear-file --clear-tags

# lifecycle
trellis rm my-notebook --force         # soft-delete to trash
trellis restore my-notebook            # restore from trash
trellis purge my-notebook --force      # permanent delete
trellis restore --uuid <node-uuid>     # disambiguate duplicate slugs
trellis purge --uuid <node-uuid> --force

# edge/annotation maintenance
trellis link-update --edge-id <edge-uuid> --label "confidence:high"
trellis unlink --edge-id <edge-uuid>
trellis annotation add my-notebook "Check residuals" --tags review
trellis annotation list my-notebook --json
trellis annotation rm <annotation-uuid>

# history (mutation log)
trellis history my-notebook
trellis history --actor-id my-agent --operation create,update --since 2025-01-01 --json

# explicit local-first checkpoint/sync flow
trellis export --path .trellis/outgoing/checkpoint.jsonl
trellis import --path .trellis/outgoing/checkpoint.jsonl

# kernel registration for Jupyter
trellis kernel register trellis-demo --display-name "Python (trellis-demo)"
trellis kernel register my-env --python /path/to/python --sys-prefix

# serve GUI/API
trellis serve [--port PORT] [--host HOST] [--debug] [--insecure-expose]

Notes:

  • SQLite is the live local source of truth during editing.
  • export/import are explicit checkpoint/sync operations.
  • Non-project/non-concept node types require a parent (--parent <slug> or --parent-uuid <uuid>).
  • reference is the canonical external-source node type; paper and url remain legacy compatibility aliases.
  • Reference metadata writes go through --citation, --abstract, and --metadata; direct CLI --uri mutation is removed.

Graph Query Commands

Use these commands to pull bounded context for humans or agents without dumping the whole ledger:

# global text search over nodes, edges, and annotations
trellis grep "quantity" --json
trellis grep "quantity" --scope node --scope annotation --json

# retrieve context around one node
trellis subgraph phase-3b --mode hierarchy --depth 2 --json
trellis subgraph phase-3b --mode edges --depth 2 --direction both --json
trellis subgraph phase-3b --mode edges --relationship references --summary

# pipe a bounded node set into grep
trellis subgraph phase-3b --mode edges --depth 2 --ids \
  | trellis grep quantity --stdin-ids --json

# export an importable bounded context
trellis subgraph export phase-3b --mode edges --depth 2 --path context.jsonl

# ask how two nodes are connected
trellis path phase-3b-transformer-training phase-3c-phylogenetic-supervision --summary
trellis path phase-1 phase-2 phase-3 --json
trellis path --uuid <id-a> --uuid <id-b> --uuid <id-c> --slugs
trellis path source-node target-node --relationship references --json

trellis subgraph answers "what context is around this node"; trellis path answers "how are these two nodes connected." subgraph --mode hierarchy follows containment, while subgraph --mode edges follows persisted graph edges. path uses unweighted shortest-path search over persisted edges; 3+ slugs or repeated --uuid values are treated as ordered waypoints.


Agent Reference

Trellis is agent-agnostic by design — any LLM or agent framework that can invoke shell commands can use Trellis directly. No plugins, no MCP server, no custom integrations required. trellis init generates a .trellis/README.md with the common operational CLI reference for agent consumption.

Contract:

  • Read: graph state (nodes/edges/annotations), mutation history, datasets, artifacts.
  • Write: annotations first, then findings/links when confidence is high.
  • Always include provenance via --actor-id.

Example agent workflow:

# read current graph state
trellis list --json
trellis find --tag review --json

# annotate a node with provenance
trellis annotate my-notebook "Residuals show seasonal drift" --tags review --actor-id agent-run-1

# create a finding when confidence is high
trellis add finding "Seasonal drift in Q3" --parent my-project --actor-id agent-run-1
trellis link seasonal-drift-in-q3 my-notebook derived_from --actor-id agent-run-1

# check mutation history
trellis history --actor-id agent-run-1 --json

Notebook Runtime Notes

  • Trellis manages one Notebook runtime per trellis serve process.
  • Notebook node file_path must be project/workspace-relative (or an absolute path that resolves under the same workspace root).
  • Kernel/environment selection is handled by Jupyter kernelspec metadata and installed kernels visible to the running Trellis environment.
  • You do not assign/create environments inside Trellis; start Trellis from the environment that has the kernels you want available.
  • If managed Jupyter startup fails, Trellis API/UI still start; notebook iframe execution is unavailable until restart with a valid runtime.

Kernel Management (Python / Conda)

Register each environment you want as a Jupyter kernel:

conda activate my-env
python -m pip install ipykernel
python -m ipykernel install --user --name my-env --display-name "Python (my-env)"

Then start Trellis from your active environment:

conda activate trellis
trellis serve

In the notebook iframe, switch kernels via Kernel -> Change kernel.

Check visible kernels:

jupyter kernelspec list

Kernel Management (R / renv)

Install and register IRkernel from the R environment you want:

R -e "install.packages('IRkernel', repos='https://cloud.r-project.org')"
R -e "IRkernel::installspec(name='ir-main', displayname='R (main)')"

For project renv, keep renv activation files in project root (.Rprofile, renv/activate.R) so notebooks use that project library context.

For .Rmd, set notebook metadata kernelspec.name to the registered R kernel, or switch it from the Jupyter kernel menu at runtime.


License

MIT + Commons Clause. See LICENSE for details.

Free for personal, academic, and internal use. You may not sell Trellis or offer it as a paid hosted service.