How to Run the Needle 2 Model Offline: Complete Guide to Local Inference
To run Needle 2 offline, pre-download the native library using fetch.fetch_library(), set the NEEDLE2_LIB_PATH environment variable to the local binary path, and instantiate the Needle class with local .cact weights to bypass all network calls.
The Needle 2 engine from the cactus-compute/needle repository operates as a native library (libneedle.*) loaded via Python's ctypes, requiring specific setup for air-gapped environments. When you understand how the wrapper locates and caches the native binary in needle/__init__.py, you can configure completely offline inference using local weight files without triggering downloads from Hugging Face.
How the Needle 2 Library Loading Works
The Python wrapper dynamically loads the native engine through a three-stage resolution process defined in needle/__init__.py.
First, the wrapper detects the model generation (2 or 3) by reading the first four bytes of the provided .cact weight file via the _weight_generation helper. If no weights are specified, it defaults to generation 2.
Next, the _library_path() function (lines 43-71) searches for the appropriate libneedle binary in this order:
- The directory specified by the
NEEDLE2_LIB_PATHorNEEDLE_LIB_PATHenvironment variable - The package installation directory
- The user cache at
~/.cache/cactus-needle/v{gen}/{version}/ - Remote download from the Hugging Face repository
Cactus-Compute/needle2(defined inENGINE_REPOSinneedle/agent/fetch.pylines 6-10)
Finally, the _lib() method creates a ctypes.CDLL instance and binds the C functions needle_init, needle_complete, and others required for inference.
Prerequisites for Offline Execution
Before running Needle 2 without internet access, ensure you have:
- The Python package installed:
cactus-needlemust be available in your environment - The native library binary: Platform-specific
libneedle.so(Linux),libneedle.dylib(macOS), orlibneedle.dll(Windows) - Compatible weights (optional): A local
.cactfile for fine-tuned inference; otherwise the engine runs with base generation 2 parameters
Step-by-Step Guide to Running Needle 2 Offline
Step 1: Install the Python Package
Install the wrapper once while you have network connectivity. This provides the Python interface and library fetching utilities.
pip install cactus-needle
Step 2: Download the Native Library Locally
Use the fetch utility in needle/agent/fetch.py to download the correct binary for your platform and store it in a directory you control.
from needle.agent import fetch
import os
# Choose a destination folder for the library
dest_dir = "./needle_lib"
# Download the generation 2 library for current OS/CPU
fetch.fetch_library(generation=2, dest_dir=dest_dir)
# Verify the file exists
lib_path = os.path.join(dest_dir, "libneedle.so") # or .dylib / .dll
print(f"Library downloaded to: {lib_path}")
This pulls the wheel from the Hugging Face repo Cactus-Compute/needle2 and writes it to your specified location without requiring manual browser downloads.
Step 3: Configure the Library Path Environment Variable
Point the wrapper to your cached binary using an environment variable. Use NEEDLE2_LIB_PATH (the newer name) or the legacy NEEDLE_LIB_PATH for backward compatibility.
# Bash / zsh - export before running Python
export NEEDLE2_LIB_PATH=$(realpath ./needle_lib/libneedle.so)
# For legacy support
export NEEDLE_LIB_PATH=$NEEDLE2_LIB_PATH
Setting this variable forces _library_path() to skip the cache check and remote download logic entirely.
Step 4: Verify Offline Loading
Confirm that the library loads without network activity by instantiating the Needle class in a fresh Python session.
import os
os.environ["NEEDLE2_LIB_PATH"] = "/absolute/path/to/needle_lib/libneedle.so"
from needle import Needle
# No weights argument defaults to generation 2
agent = Needle(tools="[]")
print("Loaded library generation:", agent._generation)
If the path is correct, this executes without attempting to download files to ~/.cache/cactus-needle/.
Step 5: Run Inference with Local Weights
Provide a local .cact file path to perform inference with fine-tuned parameters while remaining offline.
weights_path = "./my_finetuned_model.cact"
agent = Needle(tools="[]", weights=weights_path)
result = agent.complete("Explain quantum computing.", max_new_tokens=128)
print(result)
The wrapper reads the generation from the weight file header and loads the already-cached library for inference.
Complete Offline Usage Examples
Example 1: Pre-download and run base model
from needle.agent import fetch
import os
# One-time setup: download library
LIB_DIR = "./needle_lib"
fetch.fetch_library(generation=2, dest_dir=LIB_DIR)
# Configure environment
os.environ["NEEDLE2_LIB_PATH"] = f"{os.path.abspath(LIB_DIR)}/libneedle.so"
# Offline usage
from needle import Needle
agent = Needle(tools=[])
response = agent.complete("Tell me a joke.", max_new_tokens=32)
print(response)
Example 2: Offline inference with custom weights
import os
# Must set before importing Needle
os.environ["NEEDLE2_LIB_PATH"] = "/opt/needle/libneedle.so"
from needle import Needle
# Load local .cact archive (contains generation identifier in header)
weights = "/data/models/my_model.cact"
agent = Needle(tools=[], weights=weights)
result = agent.run("Schedule a meeting tomorrow at 10am.", max_steps=4)
print(result["results"])
Key Source Files and Implementation Details
Understanding these implementation files helps debug offline deployment issues:
needle/__init__.py: Contains theNeedleclass,_library_path()(lines 43-71), and_lib()functions that handle ctypes loading and generation detection from.cactfiles.needle/agent/fetch.py: Implementsfetch_library()and definesENGINE_REPOS(lines 6-10) mapping generations to Hugging Face repositories likeCactus-Compute/needle2.needle/_worker.py: Manages the fine-tuning worker process that communicates with the native engine when custom weights are provided.tests/test_inference.py: Reference implementation showing patterns forNeedle.complete()andNeedle.run()methods.
The default cache location follows the pattern ~/.cache/cactus-needle/v2/<version>/libneedle.* when downloads occur, but the NEEDLE2_LIB_PATH override bypasses this entirely.
Summary
- Needle 2 requires the native
libneedlebinary loaded via ctypes, which typically downloads from Hugging Face on first use. - Use
fetch.fetch_library()inneedle/agent/fetch.pyto pre-download the binary for your platform while online. - Set the NEEDLE2_LIB_PATH environment variable to the absolute path of
libneedle.so,.dylib, or.dllto force offline mode. - The wrapper detects model generation from the first four bytes of
.cactweight files, ensuring compatibility between your binary and weights. - With the library cached locally and the environment variable set, all subsequent instantiation of the
Needleclass operates without network connectivity.
Frequently Asked Questions
Where is the Needle 2 library cached after the first download?
When allowed to download automatically, the library is stored in the user cache directory at ~/.cache/cactus-needle/v{gen}/{version}/libneedle.*, where {gen} is the model generation (2 or 3) and {version} is the package version. However, using the NEEDLE2_LIB_PATH environment variable overrides this location and skips cache lookups entirely.
Can I use the legacy NEEDLE_LIB_PATH environment variable?
Yes. The wrapper checks for NEEDLE2_LIB_PATH first (the newer naming convention), but falls back to NEEDLE_LIB_PATH for backward compatibility. Setting either variable to the absolute path of your pre-downloaded binary will prevent network downloads.
What file format should offline weights use?
Needle 2 requires weights in the .cact format, which is a custom archive containing model parameters and a four-byte header indicating the generation. When you provide a local path to a .cact file via the weights parameter, the wrapper reads the generation identifier from the first four bytes to ensure compatibility with the loaded libneedle binary.
Does offline mode support both Needle 2 and Needle 3 generations?
Yes. The offline setup works for any generation supported by your cached library. When using the fetch.fetch_library() utility, specify generation=2 or generation=3 to download the appropriate binary. The Needle class automatically detects the required generation from the weight file header or defaults to generation 2 when no weights are provided, loading the correct cached binary accordingly.
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 →