How to Distinguish Between Needle 2 and Needle 3 Generations in Cactus Compute
Needle 2 and Needle 3 are distinguished by a 4-byte archive tag in .cact weight files, runtime environment variables, and the internal _generation attribute, with the Python package automatically selecting the correct native engine to prevent cross-generation incompatibility.
The cactus-compute/needle repository maintains two separate generations of its foundation model, each with distinct capabilities and binary requirements. When you load a model or initialize a Needle instance, the package inspects multiple signals to determine which generation is active, ensuring that generation-specific features like audio processing remain incompatible with wrong-version archives.
Archive Format Tag Detection
Every .cact weight archive begins with a 4-byte magic tag that maps directly to its generation. In needle/__init__.py, the _CACT_GENERATIONS dictionary (lines 23-26) defines these mappings:
- Generation 2: Tag
0x05E12A83 - Generation 3: Tag
0x05E12A84
The _weight_generation() function (lines 29-40) reads the first four bytes of any supplied archive and returns the corresponding integer generation. This detection runs automatically during Needle initialization before any native code loads.
import pathlib
from needle import _weight_generation
archive = pathlib.Path("my_model.cact")
gen = _weight_generation(archive) # Returns 2 or 3
print(f"Detected Needle generation: {gen}")
If you attempt to load a generation 3 archive, the package immediately knows to prepare the Needle 3 engine pipeline.
Runtime Generation Identification
Once initialized, every Needle instance exposes its generation through the _generation attribute. When you instantiate the class without providing weights, it defaults to generation 2, reflecting the historic compact 14 MB binary format.
from needle import Needle
# Default initialization (no weights)
needle2 = Needle()
print(needle2._generation) # Output: 2
# Explicit generation 3 archive
needle3 = Needle(weights="model_v3.cact")
print(needle3._generation) # Output: 3
This attribute drives all subsequent capability checks throughout the API implementation.
Native Library Path Dispatch
The package dynamically selects the appropriate shared library based on the detected generation. The _library_path() function (lines 43-73 in needle/__init__.py) constructs candidate library names (libneedle2.so or libneedle3.so) and checks environment variables before falling back to the cached engine.
You can override the library selection using generation-specific environment variables:
NEEDLE2_LIB_PATH– Path to the generation 2 native libraryNEEDLE3_LIB_PATH– Path to the generation 3 native libraryNEEDLE_LIB_PATH– Historic alias that only affects generation 2
import os
import needle
# Force a specific generation 3 library location
os.environ["NEEDLE3_LIB_PATH"] = "/opt/custom/libneedle3.so"
model = needle.Needle(weights="audio_model.cact")
API Capability Constraints
Runtime checks throughout needle/__init__.py enforce generation-specific limitations. Functions requiring generation 3 capabilities—such as embed() (lines 64-68) and internal methods like _complete() (lines 30-34)—validate the instance's _generation attribute before executing.
If you invoke a generation 3 feature on a generation 2 instance, the API raises a ValueError immediately. Conversely, generation 2-specific features (like the compact binary format) are unavailable when a generation 3 archive is loaded.
from needle import Needle
# Generation 2 instance lacks embedding support
legacy = Needle()
try:
legacy.embed("text sample")
except ValueError as e:
print("Embeddings require Needle 3") # Error raised here
Managing Binaries via CLI
The needle fetch command downloads generation-specific binaries into isolated cache directories. Use the --generation flag to explicitly target one version:
# Download Needle 2 engine to ~/.cache/cactus-needle/v2/
needle fetch --generation 2
# Download Needle 3 engine to ~/.cache/cactus-needle/v3/
needle fetch --generation 3
This ensures the correct native library is available before you instantiate any models, as documented in doc/apis.md around line 127.
Summary
- Archive inspection: The
_weight_generation()helper reads 4-byte tags (0x05E12A83for generation 2,0x05E12A84for generation 3) from.cactfiles to determine compatibility. - Instance attribute: Query
needle._generationto identify which engine is active at runtime. - Library control: Set
NEEDLE2_LIB_PATHorNEEDLE3_LIB_PATHenvironment variables to override default library discovery in_library_path(). - Feature gates: Generation 3 features (audio, embeddings) raise
ValueErrorwhen called on generation 2 instances, preventing silent failures. - Binary isolation: Use
needle fetch --generationto cache version-specific native engines in separate directories.
Frequently Asked Questions
How can I verify which generation my .cact file uses without loading it?
You can import the internal _weight_generation function from needle/__init__.py and pass it a Path object to your archive. It returns 2 or 3 based on the 4-byte header tag without initializing the full engine.
What happens if I try to use audio features on a Needle 2 model?
The API raises a ValueError during the method call. Generation 2 archives lack the necessary tensor layouts for audio processing, and the runtime checks in methods like _complete() explicitly block these operations when self._generation == 2.
Can I force Needle to use generation 3 without providing a weights file?
No. Without a .cact archive, the Needle constructor defaults to generation 2. To use generation 3 capabilities, you must supply a valid generation 3 archive, which triggers the tag detection logic and sets self._generation = 3.
Where does Needle store the downloaded native libraries for each generation?
The needle fetch command stores binaries under ~/.cache/cactus-needle/v2/ for generation 2 and ~/.cache/cactus-needle/v3/ for generation 3. The _library_path() function searches these directories automatically when resolving native library paths.
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 →