# Tool.shape
URL: https://lsd.tools/docs/api-tool-shape
Updated: 2026-07-17

## Parameters

| name | type | default | description |
|---|---|---|---|
| `dialog` | `dict \| UINode` | `None` | a UI spec overriding the auto-generated form; field names are checked against the parameters at import |
| `outputs` | `list[str]` | `None` | named output ports — the function returns `{"a": Table, …}`, selected downstream via `step.output("a")` |
| `graph_outputs` | `dict` | `None` | `{name: type}` read-only scalars set via `ctx.set_output(...)`, excluded from the cache key |
| `overrides` | `str` | `None` | make this a drop-in variant of another package's node, e.g. `"mim.clean"` |
| `override_mode` | `str` | `"replace"` | `"replace"` wins the overridden identity by default; `"coexist"` keeps both addable |

## Example

```python
@tool.shape
def keep_top(t: Table, cutoff: int = 10) -> Table:
    return t.filter(t["score"] >= cutoff)
```

Ship a coexisting alternative to another package's node:

```python
@tool.shape(overrides="mim.clean", override_mode="coexist")
def clean(t: Table) -> Table:
    return t.drop_null()
```

## Notes

Every `Table`-annotated parameter becomes a wired input port; wire it by passing the upstream step
instance as that keyword. A `StepContext` parameter may be injected, but a `Context` parameter is
rejected. `override_mode` is `"replace"` (default) or `"coexist"`.

## See also

**API:** [load](/docs/api-tool-load) · [deliver](/docs/api-tool-deliver) · [Table](/docs/api-table)

**Guides:** [Shape steps](/docs/tools-shape) · [Parameters vs ports](/docs/tools-params-ports) · [Clean a CSV](/docs/ex-clean-csv)
