# How to Use Raw JSON Schema for Tool Definitions in Needle 2

> Learn to use raw JSON schema for tool definitions in Needle 2. Directly pass schemas via the tools parameter for validation and decoding without the @needle.tool decorator.

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

---

**Needle 2 accepts hand-written JSON schemas directly via the `tools` parameter, bypassing the `@needle.tool` decorator while maintaining the same validation and grammar-constrained decoding pipeline.**

While Needle 2 typically discovers tools through the `@needle.tool` decorator—which internally calls `build_schema` in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) to inspect function signatures—you can supply raw JSON schema definitions directly. This is essential when integrating tools that live outside your codebase, generating schemas dynamically, or requiring explicit control over parameter descriptions and constraints.

## Structure of a Valid Tool Schema

A raw JSON schema passed to `needle.Needle` must match the structure produced by `build_schema` in [[`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py)](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py#L10-L41). The schema requires three top-level keys:

- **`name`**: The string identifier the model uses to invoke the function.
- **`description`**: Optional human-readable text shown to the model to guide tool selection.
- **`parameters`**: A JSON Schema object containing `type: "object"`, a `properties` dictionary mapping argument names to their schemas, and an optional `required` array listing mandatory parameters.

Inside each property definition, you can specify standard JSON Schema types (`string`, `integer`, `boolean`, etc.) and validation constraints equivalent to `needle.Field` annotations, including `description`, `enum`, `gt`, `lt`, `pattern`, and `minLength`.

## Defining Tools with Raw JSON

You can provide schemas as inline Python dictionaries, load them from external files, or mix them with decorator-generated definitions.

### Inline Dictionary Definition

Define the schema directly in Python code as a list of dictionaries. This pattern appears in the official documentation at [[`doc/apis.md`](https://github.com/cactus-compute/needle/blob/main/doc/apis.md)](https://github.com/cactus-compute/needle/blob/main/doc/apis.md#L51-L68):

```python
import needle

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

agent = needle.Needle(tools=tools)
agent.run("turn the kitchen lights on at 70%")

```

The schema is passed directly to the `Needle` constructor, bypassing the decorator entirely while using the same internal grammar-generation pipeline.

### Loading from External JSON Files

For large tool catalogs, store schemas in a JSON file and load them at runtime:

```python
import json
import needle

with open("tools.json") as f:
    schema = json.load(f)

agent = needle.Needle(tools=schema)
print(agent.run("dim the living room lights to 30"))

```

The [`tools.json`](https://github.com/cactus-compute/needle/blob/main/tools.json) file must contain an array of schema objects identical in structure to the inline example above.

### Combining Manual and Decorator-Generated Schemas

Needle 2 allows mixing automatically generated schemas with hand-written ones. The decorator stores the generated schema in the `_needle_tool` attribute of the decorated function (as implemented in [[`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py)](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py#L62-L65)):

```python
@needle.tool
def send_money(amount: float, to: str):
    """Send money to a user."""
    return {"sent": amount, "to": to}

# Hand-written schema for a second tool

extra = [{
    "name": "set_thermostat",
    "description": "Set the thermostat temperature.",
    "parameters": {
        "type": "object",
        "properties": {
            "temperature": {"type": "integer"},
            "mode": {"type": "string", "enum": ["heat", "cool", "auto"]},
        },
        "required": ["temperature"],
    },
}]

# Merge decorator-generated and manual schemas

all_tools = [send_money._needle_tool] + extra
agent = needle.Needle(tools=all_tools)

```

This hybrid approach lets you extend the agent with external tool definitions while keeping native Python functions for internal logic.

## Validation Constraints in Raw Schemas

When writing raw JSON schemas, you can enforce the same validation rules that `needle.Field` provides. The `parameters.properties` dictionary supports standard JSON Schema validation keywords:

- **`enum`**: Restrict values to a specific set.
- **`minimum`**, **`maximum`**, **`exclusiveMinimum`**, **`exclusiveMaximum`**: Numeric range constraints (equivalent to `gt`, `lt`).
- **`minLength`**, **`maxLength`**: String length constraints.
- **`pattern`**: Regular expression validation for strings.

These constraints are evaluated during the agent's validation phase, ensuring that tool arguments meet your specifications before execution.

## Summary

- **Raw JSON schemas** bypass the `@needle.tool` decorator while maintaining full compatibility with Needle 2's validation and grammar-constrained decoding.
- **Required structure**: Each tool requires `name`, optional `description`, and `parameters` containing `type: "object"`, `properties`, and optional `required`.
- **Storage location**: Decorated functions store their generated schema in `fn._needle_tool`, allowing manual mixing with external definitions.
- **Validation support**: Raw schemas support the same constraints as `needle.Field`, including `enum`, range limits, and pattern matching.
- **Source files**: Core logic resides in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) (lines 10-41 and 62-65), with documentation examples in [`doc/apis.md`](https://github.com/cactus-compute/needle/blob/main/doc/apis.md) (lines 51-68).

## Frequently Asked Questions

### What is the exact structure required for a raw JSON tool schema in Needle 2?

A valid schema must be a dictionary containing `name` (string), optional `description` (string), and `parameters` (object). The `parameters` object must declare `type: "object"` and contain a `properties` dictionary mapping argument names to their type definitions, plus an optional `required` array listing mandatory arguments. This structure mirrors the output of `build_schema` in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py).

### Can I mix manually written schemas with the @needle.tool decorator?

Yes. Access the decorator-generated schema via the `_needle_tool` attribute on the decorated function, then combine it with manual schemas in a single list passed to `needle.Needle(tools=...)`. The agent processes both sources through the identical validation pipeline.

### Where does Needle 2 store the automatically generated schema on decorated functions?

The `@needle.tool` decorator attaches the generated schema to the function object under the attribute `_needle_tool`. You can access this attribute to retrieve the JSON schema dictionary for inspection or manual merging, as implemented in lines 62-65 of [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py).

### Does using a raw JSON schema affect grammar-constrained decoding or validation?

No. Needle 2 treats manually supplied schemas exactly like automatically generated ones. Both feed into the same grammar-generation and validation pipeline defined in the agent's tool processing logic, ensuring consistent confidence-gated execution regardless of how the schema was created.