How to Integrate Needle 2 into Your Python Project: A Complete Implementation Guide
Integrate Needle 2 into your Python project by installing the cactus-needle package, defining tools with the @needle.tool decorator, and instantiating the Needle agent to run offline inference loops.
Needle 2 is a local-first agentic inference engine developed by cactus-compute/needle that executes Python functions through a model-driven tool-selection loop without network dependencies after initial setup. This guide covers the complete integration workflow from installation to production deployment using the exact APIs implemented in the source code.
Installation and Dependencies
Install the base inference engine from PyPI. The package name is cactus-needle, which provides the top-level needle module.
pip install cactus-needle
For advanced use cases, install optional extras based on your hardware requirements:
pip install "cactus-needle[train]"— Enables LoRA fine-tuning capabilitiespip install "cactus-needle[train,gpu]"— Adds GPU acceleration for training workloadspip install "cactus-needle[train,metal]"— Apple Silicon (Metal) support for training
The engine automatically downloads a 14 MB shared library from Hugging Face on first use and caches it at ~/.cache/cactus-needle/. After this initial fetch, all inference runs completely offline.
Core Architecture and Source Files
Understanding the main components helps navigate the codebase effectively. The public API is centralized in needle/__init__.py, while tool handling resides in needle/agent/tools.py.
| Component | Source Location | Purpose |
|---|---|---|
needle.Needle class |
needle/__init__.py (lines 56-73 constructor, 75-99 binding) |
Creates the agent, manages the inference engine, and loads optional .cact tuned weights |
@needle.tool decorator |
needle/agent/tools.py |
Converts Python functions into JSON-schema tools the model can invoke |
needle.Field |
needle/agent/tools.py |
Defines per-argument constraints (range, pattern, enum) compiled into the decode grammar |
agent.run() |
needle/__init__.py (lines 39-61) |
High-level agentic loop that auto-executes tools and aggregates results |
agent.complete() |
needle/__init__.py (lines 19-31) |
Single-turn completion for manual loop control |
needle.extract() |
needle/__init__.py (line 79) |
One-shot structured extraction using Pydantic models |
Defining Tools and Creating the Agent
Step 1: Decorate Python Functions as Tools
Use the @needle.tool decorator to expose Python functions to the model. The system automatically generates JSON schemas from type hints and docstrings.
import needle
from typing import Literal, Annotated
@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}
Add optional constraints using needle.Field for arguments requiring validation:
@needle.tool
def set_volume(
level: Annotated[int, needle.Field(ge=0, le=100)]
):
"""Set volume level."""
return {"level": level}
Step 2: Instantiate the Needle Agent
Create a Needle instance by passing your tool list and optional system facts. According to the source in needle/__init__.py, the constructor accepts a system string for context (date, device, battery) and an optional weights path to a tuned .cact file.
agent = needle.Needle(
tools=[set_thermostat],
system="date: 2026-09-02; device: laptop; battery: 85%"
)
Executing Inference
Automatic Agentic Loop with run()
The agent.run() method implements the full inference loop defined in needle/__init__.py lines 39-61. It selects tools, executes Python functions, feeds results back to the model, and returns aggregated results.
response = agent.run("Make it 22 degrees and cool the room")
print(response["results"])
# → [{'temperature': 22, 'mode': 'cool'}]
Single-Turn Control with complete()
For manual loop management, use agent.complete() (implemented in lines 19-31 of needle/__init__.py). This executes exactly one model inference turn without automatic tool execution.
result = agent.complete("What tools are available?")
Structured Extraction with extract()
For one-shot data extraction without defining explicit tools, use needle.extract(). This shortcut accepts a Pydantic model and returns validated instances.
from pydantic import BaseModel
class Invoice(BaseModel):
vendor: str
total: float
due_date: str
invoice = needle.extract(
"Invoice from Acme Corp, $1,200.00, due 2026-10-01",
Invoice
)
print(invoice)
# → vendor='Acme Corp' total=1200.0 due_date='2026-10-01'
Leveraging Pre-Built Environments
The repository ships with ready-made environment modules in needle/environments/ that bundle curated toolsets for common domains. Import these directly to skip tool definition.
from needle.environments import smart_home
# Run inference using the built-in smart home toolset
smart_home.agent.run("Dim the study lights to 30 percent")
# Validate environment integrity
smart_home.run_tests()
Available environments include smart_home and media_player, documented in doc/environments.md.
Fine-Tuning and Custom Weights
To integrate a custom fine-tuned model, first complete the LoRA training workflow described in doc/finetuning.md, then build a .cact archive:
needle build checkpoints/base.pkl --lora checkpoints/needle_lora.pkl --out my_needle.cact
Load the tuned weights by passing the file path to the Needle constructor:
agent = needle.Needle(
tools=[set_thermostat],
weights="my_needle.cact"
)
Summary
- Install the
cactus-needlepackage with optional[train],[gpu], or[metal]extras for hardware-specific capabilities - Define tools using
@needle.toolinneedle/agent/tools.pystyle, with optionalneedle.Fieldconstraints for validation grammar - Create agents via
needle.Needleclass inneedle/__init__.py, passing tool lists and system context strings - Execute using
agent.run()for automatic loops,agent.complete()for single-turn control, orneedle.extract()for Pydantic-based extraction - Deploy offline after the engine binary caches at
~/.cache/cactus-needle/, enabling inference without network traffic - Extend with pre-built environments from
needle/environments/or custom.cactweights from LoRA fine-tuning
Frequently Asked Questions
What is the difference between agent.run() and agent.complete()?
agent.run() implements the full agentic loop defined in needle/__init__.py lines 39-61, automatically selecting tools, executing Python functions, and feeding results back until the model returns a final response. agent.complete() (lines 19-31) performs a single inference turn without executing tools or managing conversation state, giving you manual control over the interaction flow.
How do I constrain tool parameters to specific values?
Use needle.Field (implemented in needle/agent/tools.py) to add per-argument constraints such as ge (greater than or equal), le (less than or equal), pattern (regex), or enum. These constraints compile into the model's decode grammar, ensuring valid outputs without post-validation.
Can Needle 2 run completely offline?
Yes. After the initial installation, the engine downloads a 14 MB binary from Hugging Face and caches it at ~/.cache/cactus-needle/. According to the "Offline devices" section in doc/apis.md, all subsequent inference runs locally without network traffic, making it suitable for air-gapped or mobile deployments.
How do I deploy a fine-tuned model in production?
First, complete the LoRA fine-tuning workflow documented in doc/finetuning.md to generate a LoRA checkpoint. Then use the CLI command needle build to package the base weights and LoRA adapter into a single .cact file. In your Python project, pass the path to this file as the weights parameter when instantiating needle.Needle, as implemented in the constructor at needle/__init__.py lines 56-73.
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 →