needle-go is a small Go binding for the published MIT needle-rs C ABI. It
uses ebitengine/purego, not cgo, to
load the 26M-parameter Needle tool-calling model and expose a typed Go API
without embedding the 22 MiB model weights in this repository.
The first ZIP supplied for this project contained documentation only. A later
ZIP included a pure-Go scaffold, but its clean-room verification failed with
an import cycle and compiler errors; it also still contains TODOs for weight
loading and the output projection. The verification record is in
PUREGO_VERIFICATION.md. This repository therefore ships the executable FFI
integration instead of presenting an unverified scaffold as a complete model
runtime.
- Go 1.26 or newer
- One supported target: Linux amd64/arm64, macOS amd64/arm64, or Windows amd64
- The matching
needle-rsv0.1.0 native library needle.safetensorsandvocab.txtfromAbdalrahman/needle-rs-safetensors
Run this from the repository root:
./scripts/fetch-assets.shThe script detects OS and CPU architecture, downloads the matching library, downloads the model at a pinned Hugging Face revision, and verifies all three files against SHA-256. If Hugging Face is not directly reachable, use a compatible mirror:
NEEDLE_MODEL_BASE_URL=https://hf-mirror.com ./scripts/fetch-assets.shOpen PowerShell in the repository root and run:
Set-ExecutionPolicy -Scope Process Bypass
.\scripts\fetch-assets.ps1The current upstream release provides a Windows amd64 DLL. The script rejects other Windows architectures instead of downloading an incompatible binary.
After either script finishes, the assets/ directory contains:
assets/
libneedle_c.so # Linux
libneedle_c.dylib # macOS
needle_c.dll # Windows
needle.safetensors # 22 MiB model weights
vocab.txt # model vocabulary
SHA256SUMS
The script verifies the release library and records the model checksums in
assets/SHA256SUMS. Do not commit the model files; they are intentionally
ignored by Git.
CGO_ENABLED=0 go run ./cmd/needle-cli \
-weights assets/needle.safetensors \
-vocab assets/vocab.txt \
-query 'What is the weather in Paris?' \
-tools '[{"name":"get_weather","description":"Get weather","parameters":{"type":"object","properties":{"location":{"type":"string"}}}}]'The output is the model's structured JSON tool call. The CLI validates that the output is valid JSON before printing it.
The same flow is available as a complete Go example:
CGO_ENABLED=0 go run ./examples/basicimport (
"context"
"path/filepath"
needle "github.com/lib-x/needle-go"
)
engine, err := needle.Open(needle.Config{
LibraryPath: filepath.Join("assets", needle.NativeLibraryFilename()),
WeightsPath: "assets/needle.safetensors",
VocabPath: "assets/vocab.txt",
})
if err != nil { /* handle error */ }
defer engine.Close()
result, err := engine.Run(ctx, "What is the weather in Paris?", toolsJSON)Engine.Run rejects oversized input and malformed tool JSON before crossing
the native boundary. The native output is also checked for valid JSON.
CGO_ENABLED=0 go test ./...
CGO_ENABLED=0 go build ./...
go test ./...
go test -race ./...
go vet ./...
go build ./...
NEEDLE_RUN_E2E=1 go test ./... -run TestModelInferenceThe first two commands prove the purego/no-cgo path. The E2E command is the real model check and requires assets fetched above. On Linux amd64 it has been verified to produce:
[{"name":"get_weather","arguments":{"location":"Paris"}}]Cross-compilation checks:
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build ./...
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build ./...
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build ./...
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build ./...