How to Manually Define Tool Schemas as JSON in Needle 2: A Complete Guide
You can bypass the @needle.tool decorator and supply a JSON schema directly to needle.Needle(tools=...) using the same structure that build_schema generates internally, containing name, description, and a JSON Schema parameters object.
Needle 2 is an open-source agent framework that discovers tools through JSON-encoded schemas. While the @needle.tool decorator automatically generates these schemas from Python functions, many production scenarios require you to manually define tool schemas as JSON in Needle 2—whether the tool lives outside your codebase, is dynamically generated, or requires explicit control over the interface exposed to the LLM.
Understanding the JSON Schema Structure
According to the source code in needle/agent/tools.py, the build_schema function produces a specific JSON structure that you must replicate when defining schemas manually. The schema must be a dictionary containing three top-level keys:
name: The function identifier the model will invokedescription: Human-readable documentation shown to the LLM (optional but recommended)parameters: A JSON Schema object withtype: "object", apropertiesmap, and optionally arequiredlist
Inside each property definition, you can specify standard JSON Schema types (string, integer, boolean, etc.) and validation constraints such as description, enum, minimum, maximum, pattern, and minLength.
Creating Hand-Written Tool Schemas
Basic JSON Structure
The documentation in doc/apis.md demonstrates the canonical format for manual schema definition. Here is a complete example showing a set_lights tool:
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 agent treats this hand-written schema exactly like one generated by the decorator, using the same grammar-constrained decoding and validation pipeline internally.
Loading Schemas from External JSON Files
For large tool catalogs or configuration-driven deployments, store your schemas in a separate JSON file:
import json
import needle
# tools.json contains an array of schemas
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"))
This approach keeps your Python code clean while allowing non-developers to modify tool definitions.
Combining Decorator-Generated and Manual Schemas
You can mix automatically generated schemas with hand-written ones by accessing the _needle_tool attribute that the decorator attaches to functions. As implemented in needle/agent/tools.py at lines 62-65, the @needle.tool decorator stores the output of build_schema(fn) in fn._needle_tool:
@needle.tool
def send_money(amount: float, to: str):
"""Send money to a user."""
return {"sent": amount, "to": to}
# Hand-written schema for external service
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 automatic and manual schemas
all_tools = [send_money._needle_tool] + extra
agent = needle.Needle(tools=all_tools)
Key Implementation Details
The core logic resides in needle/agent/tools.py, where the build_schema function (lines 10-41) inspects function signatures and docstrings to generate compliant JSON. When you manually define tool schemas as JSON in Needle 2, you bypass this introspection but must ensure your JSON conforms to the exact structure expected by the agent's validation logic.
The parameters object follows standard JSON Schema draft specifications, allowing you to define complex nested objects, arrays, and validation constraints. The agent uses these schemas for both LLM grammar generation at inference time and runtime parameter validation before tool execution.
Summary
- Manually define tool schemas as JSON in Needle 2 by providing a list of dictionaries with
name,description, andparameterskeys toneedle.Needle(tools=...). - The
parametersfield must be a valid JSON Schema object withtype: "object", apropertiesmap, and arequiredarray listing mandatory arguments. - Store schemas in external JSON files for dynamic loading or mix manual schemas with decorator-generated ones using the
_needle_toolattribute. - The source implementation in
needle/agent/tools.pyensures that manual and automatic schemas follow identical validation and grammar-generation pipelines.
Frequently Asked Questions
What is the exact JSON structure required for Needle 2 tool schemas?
The schema must be a dictionary containing name (string), description (string), and parameters (object). The parameters object must specify type: "object", include a properties dictionary mapping argument names to their schema definitions, and optionally list required fields in a required array. This structure mirrors the output of build_schema in needle/agent/tools.py.
Can I use JSON Schema validation keywords like minimum and pattern in hand-written schemas?
Yes. Since the parameters field accepts standard JSON Schema, you can use any validation keywords supported by the specification, including minimum, maximum, pattern, minLength, maxLength, and enum. These constraints are respected during both LLM grammar generation and runtime parameter validation.
How do I combine Python functions decorated with @needle.tool and external JSON schemas?
Access the automatically generated schema via the _needle_tool attribute attached to decorated functions, then concatenate it with your manual schema list. The decorator stores the result of build_schema(fn) at fn._needle_tool (lines 62-65 of needle/agent/tools.py), allowing seamless integration of both approaches.
Where can I find the official example of a hand-written tool schema?
The canonical example appears in doc/apis.md (lines 51-68) within the cactus-compute/needle repository. This documentation demonstrates the complete JSON structure for manual tool definitions and explains how the Needle class consumes these schemas.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →