All docs
The Tool object
Every LSD package has one Tool at module scope — it names your nodes, collects each decorated step, and mounts them into the host at load.
A Tool is the one registry object a package hands to LSD. You create it once, at module
scope, and every @tool.* decorator you write attaches a node, command, or view to it.
Usage#
from lsdtools import Tool, Table
tool = Tool("hello", label="Hello")
@tool.load
def numbers(n: int = 5) -> Table:
return Table({"i": list(range(n))})
# → a node "hello.numbers" appears in the add-node palette
Tool("hello") sets the package's name; label="Hello" is the human title shown in the UI
(it defaults to the name).
One Tool per package#
Create exactly one Tool per package, at module scope — never inside a function. Its name is
the namespace for everything the package contributes, so a second Tool would split your nodes
across two namespaces. Decorators register their target the moment the module is imported, so all a
package needs to expose a node is the decorated function sitting under tool.
Node identity#
Every step's identity is f"{tool_name}.{fn_name}" — the tool name joined to the decorated
function's name:
tool = Tool("hello")
@tool.shape
def top(t: Table, limit: int = 3) -> Table: # identity → "hello.top"
return t.sort("i", descending=True).head(limit)
This string is stable: it keys the node in saved projects, in the palette, and in cross-package
references. Node variants use it as the target of overrides=, and
renaming a function changes the identity — so treat function names as part of your public surface.
Mounting#
Steps and entity types register at decoration time. The interactive surfaces — commands,
views (sidebar, overlay, and editor placements), actions, and templates — are collected on the Tool and
flushed into the host by tool.mount():
tool.mount(host, package="hello") # the loader calls this for you
The package loader calls mount() when your package loads, attributing every contribution to the
package id so it can be cleanly removed later. You only call mount() by hand in a standalone
script or a test harness. tool.dispatch(route, ...) and tool.contribute(...) round out the
object — see Commands & actions.
Related#
Learn — Parameters vs ports · Load steps · Node variants
Examples — Your first tool · A complete package
Frequently asked questions
How many Tool objects should a package have?
Exactly one, created at module scope. Its name namespaces every node in the package, so a second Tool would fragment your node identities and confuse the loader.
Do I have to call tool.mount() myself?
No. The package loader calls mount() when the package is loaded, attributing every contribution to the package so it can be cleanly unmounted. You only call it by hand in a standalone script or a test.