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 capabilities
  • pip install "cactus-needle[train,gpu]" — Adds GPU acceleration for training workloads
  • pip 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-needle package with optional [train], [gpu], or [metal] extras for hardware-specific capabilities
  • Define tools using @needle.tool in needle/agent/tools.py style, with optional needle.Field constraints for validation grammar
  • Create agents via needle.Needle class in needle/__init__.py, passing tool lists and system context strings
  • Execute using agent.run() for automatic loops, agent.complete() for single-turn control, or needle.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 .cact weights 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →