# The Tool object
URL: https://lsd.tools/docs/tools-tool-object
Updated: 2026-07-18

> A Tool is the single registry object for a package. Create one at module scope, decorate functions with @tool.load / shape / deliver, and each becomes a node whose identity is "toolname.funcname". The loader calls tool.mount() to surface commands, views and actions into the host.

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

```python
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:

```python
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](/docs/tools-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()`:

```python
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](/docs/tools-commands-actions).

## Related

**Learn** — [Parameters vs ports](/docs/tools-params-ports) · [Load steps](/docs/tools-load) · [Node variants](/docs/tools-variants)

**API** — [Tool](/docs/api-tool) · [Context](/docs/api-context) · [Table](/docs/api-table)

**Examples** — [Your first tool](/docs/ex-hello-tool) · [A complete package](/docs/ex-full-package)

## FAQ
### 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.
