# How to Declare Tools in Needle 2: 3 Methods Explained

> Discover three methods for declaring tools in Needle 2: use the @needle.tool decorator, Pydantic models, or raw JSON schemas. Integrate tools seamlessly into your workflows.

- Repository: [Cactus Compute, Inc./needle](https://github.com/cactus-compute/needle)
- Tags: how-to-guide
- Published: 2026-08-24

---

**In Needle 2, you declare tools using the `@needle.tool` decorator on Python functions, passing Pydantic models, or providing raw JSON schemas, then supply them to the `Needle` constructor via the `tools` parameter.**

The cactus-compute/needle repository provides a lightweight framework for building conversational AI agents. Declaring tools in Needle 2 follows a two-step pattern where you first define the tool schema and then register it with the agent.

## Using the @needle.tool Decorator

The primary method for declaring tools involves applying the `@needle.tool` decorator to Python functions. According to the source code in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) (lines 68-71), this decorator introspects function signatures, type hints, and docstrings to automatically generate JSON Schema definitions.

### Converting Functions to Tool Schemas

When you decorate a function with `@needle.tool`, the framework inspects the callable and stores the generated schema as `fn._needle_tool`. The decorator extracts parameter types from annotations and descriptions from the docstring's Args section.

```python
@needle.tool
def set_thermostat(temperature: int,
                   mode: Literal["heat", "cool", "auto"] = "auto"):
    """Set the thermostat.

    Args:
        temperature: target temperature in Celsius
        mode: heating strategy to use
    """
    return {"temperature": temperature, "mode": mode}

```

### Registering Tools with the Agent

After decorating your functions, pass them to the `Needle` constructor using the `tools` parameter. As documented in [`doc/apis.md`](https://github.com/cactus-compute/needle/blob/main/doc/apis.md) (line 5), the constructor accepts a list of tool definitions.

```python
agent = needle.Needle(tools=[set_thermostat])
agent.run("make it 21 and cool the room")

```

## Alternative Declaration Methods

Needle 2 supports three alternative approaches for declaring tools beyond the standard decorator pattern.

### Direct JSON Schema

You can bypass Python function definitions entirely by constructing raw JSON Schema dictionaries. This method is documented in [`doc/apis.md`](https://github.com/cactus-compute/needle/blob/main/doc/apis.md) (lines 51-68) and passed directly to the `tools` parameter.

```python
tools = [{
    "name": "set_lights",
    "description": "Turn a room's lights on/off and set brightness",
    "parameters": {
        "type": "object",
        "properties": {
            "room": {"type": "string", "description": "room name"},
            "on": {"type": "boolean"},
            "brightness": {"type": "integer", "minimum": 0, "maximum": 100},
        },
        "required": ["room", "on"],
    },
}]

agent = needle.Needle(tools=tools)
agent.run("Dim the living room lights to 30%")

```

### Pydantic Models

For complex validation scenarios, define tools using **Pydantic models**. The framework extracts JSON schemas from `BaseModel` subclasses via the `pydantic_schema` function in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py).

### Field Constraints with typing.Annotated

Use `typing.Annotated` combined with `needle.Field` to specify per-argument validation rules such as numeric ranges, regex patterns, and string lengths. This approach is detailed in [`doc/apis.md`](https://github.com/cactus-compute/needle/blob/main/doc/apis.md) (lines 34-48).

```python
from typing import Annotated

@needle.tool
def send_money(
    amount: Annotated[float, needle.Field(gt=0, le=10000,
                                         description="USD, up to 10,000")],
    to:     Annotated[str,   needle.Field(pattern=r"^@[a-z0-9_]+$",
                                         description="recipient handle")],
    memo:   Annotated[str,   needle.Field(max_length=80)] = "",
):
    """Send money to a handle."""
    return {"sent": amount, "to": to}

agent = needle.Needle(tools=[send_money])
agent.run("Send $25 to @bob")

```

## Complete Working Examples

Here are runnable patterns demonstrating each declaration style:

**Simple Function Tool:**

```python
@needle.tool
def greet(name: str):
    """Say hello to someone."""
    return f"Hello, {name}!"

agent = needle.Needle(tools=[greet])
response = agent.run("Hey, can you greet Alice?")

```

## Summary

- **The `@needle.tool` decorator** (implemented in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py)) automatically generates JSON schemas from Python function signatures and docstrings
- **Tool registration** requires passing decorated functions to the `Needle` constructor via the `tools` parameter
- **Three declaration methods** are supported: decorated functions, raw JSON schemas, and Pydantic models
- **Validation constraints** can be added using `typing.Annotated` with `needle.Field` for granular control over argument validation

## Frequently Asked Questions

### What file contains the tool decorator implementation?

The `@needle.tool` decorator is implemented in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) (lines 68-71). This module handles function introspection, schema generation, and the `Field` constraint helper used with `typing.Annotated`.

### Can I use Pydantic models instead of functions to declare tools?

Yes. Needle 2 accepts Pydantic `BaseModel` classes as tools. The framework uses the `pydantic_schema` function in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) to extract JSON schemas from model definitions, providing an alternative to the decorator-based approach for complex data structures.

### How do I add validation constraints to tool arguments?

Use `typing.Annotated` combined with `needle.Field` to specify constraints like numeric ranges (`gt`, `le`), regex patterns (`pattern`), or length limits (`max_length`). As shown in [`doc/apis.md`](https://github.com/cactus-compute/needle/blob/main/doc/apis.md) (lines 34-48), these annotations integrate directly with the `@needle.tool` decorator to enforce validation at the schema level.

### Does Needle 2 support raw JSON schema definitions?

Yes. You can pass raw JSON Schema dictionaries directly to the `Needle` constructor via the `tools` parameter. This approach, documented in [`doc/apis.md`](https://github.com/cactus-compute/needle/blob/main/doc/apis.md) (lines 51-68), allows integration with external schema definitions or languages other than Python.