HyperView docs

HyperView · Guides

Extensions, tools and panels

Add your own computations and views to HyperView with a folder of Python and JSX — no frontend fork, no build step.

Extensions ship things, tools compute things, panels show things.

An extension is a folder you keep in your own repository, usually under .hyperview/extensions/. It contributes tools, panels or both. HyperView loads it at runtime: no frontend fork, no build step, no change to HyperView itself.

.hyperview/extensions/selection-profile/
  extension.toml
  tools.py
  panel.jsx

Tools

A tool is a Python function that takes JSON parameters and returns JSON:

from hyperview.tools import RunContext, tool

@tool("selection_profile.summarize")
def summarize(ctx: RunContext, *, top_k: int = 10) -> dict:
    ids = list(ctx.workspace.ui.selected_ids)
    return {"selected": len(ids), "dataset": ctx.dataset.name}

RunContext gives the tool the active dataset and workspace. A tool has no UI, so it must make sense when called headlessly: from a panel, the CLI (hyperview tools run), a notebook or a coding agent. That makes every tool an agent tool by construction.

Panels

A panel is a view in the workspace. Its renderer is a JSX module whose default export is a React component built from window.HyperViewPanelSDK:

const { React, components, hooks } = globalThis.HyperViewPanelSDK;
const { Panel, PanelHeader } = components;
const { useSelection, useTool } = hooks;

export default function SelectionProfile({ panelId }) {
  const { selectedIds } = useSelection();
  const { runTool } = useTool();
  const [summary, setSummary] = React.useState(null);

  return (
    <Panel>
      <PanelHeader title="Selection profile" />
      <p>{selectedIds.length} selected</p>
      <button onClick={async () => setSummary(await runTool("selection_profile.summarize"))}>
        Summarize
      </button>
      {summary && <pre>{JSON.stringify(summary, null, 2)}</pre>}
    </Panel>
  );
}

The SDK provides hooks for selection, collections, panel state (usePanelState) and tools (useTool), and the same Panel, PanelHeader and toolbar components the built-in panels use. Panels read data through the SDK rather than raw fetch, which is what lets them work unchanged in a Static Space.

The manifest

name = "selection-profile"
description = "Summarize the current selection"

[[tools]]
file = "tools.py"

[[panels]]
id = "selection-profile"
title = "Selection profile"
position = "right"
file = "panel.jsx"

A panel that cannot work without a server — because it calls a tool, for example — declares it, and a Static Space shows the reason instead of a broken panel:

static_compatible = false
static_reason = "Requires the selection_profile.summarize tool."

Load an extension

hyperview extension add .hyperview/extensions/selection-profile --workspace demo --add-panels

or from Python, before the workspace opens:

hv.launch(dataset, extensions=[".hyperview/extensions/selection-profile"])

HyperView ships a complete worked example, the reference extension: hyperview extension add --shipped reference --workspace demo.

Arrange panels with a view

An extension says a panel exists; a view says which panels open, where, and in what state:

view = hv.ui.View(
    hv.ui.Horizontal(
        hv.ui.Samples(id="results"),
        hv.ui.Scatter(id="map", title="Map", layout_key=layout_key),
    ),
    hv.ui.ExtensionPanel(
        id="profile",
        extension="selection-profile",
        panel="selection-profile",
        position="right",
    ),
)
hv.launch(dataset, view=view, extensions=[".hyperview/extensions/selection-profile"])

Two rules of thumb

  1. If it computes, it is a tool. A panel renders data it can get from the SDK; anything that needs the live dataset or a model belongs in a tool the panel calls.
  2. Precompute for sharing. Static Spaces run panels but not tools, so put the interesting results into collections or panel state before you export.
Edit this page on GitHub