CactusNeedleSharp 0.2.0
dotnet add package CactusNeedleSharp --version 0.2.0
NuGet\Install-Package CactusNeedleSharp -Version 0.2.0
<PackageReference Include="CactusNeedleSharp" Version="0.2.0" />
<PackageVersion Include="CactusNeedleSharp" Version="0.2.0" />
<PackageReference Include="CactusNeedleSharp" />
paket add CactusNeedleSharp --version 0.2.0
#r "nuget: CactusNeedleSharp, 0.2.0"
#:package CactusNeedleSharp@0.2.0
#addin nuget:?package=CactusNeedleSharp&version=0.2.0
#tool nuget:?package=CactusNeedleSharp&version=0.2.0
CactusNeedleSharp
Unofficial .NET wrapper for Needle 2 by Cactus Compute.
CactusNeedleSharp exposes Needle's local, schema-constrained tool calling and structured extraction capabilities to .NET applications.
Needle 2 is developed by Cactus Compute. This project is an independent community integration and is not affiliated with, sponsored by, or endorsed by Cactus Compute.
User / LLM intent
│
▼
CactusNeedleSharp
├─ tool selection
├─ argument extraction
├─ schema-constrained decoding
└─ confidence
▼
Typed ToolCall
Needle decides how an intent maps to a declared operation. Your application decides whether the operation is permitted and whether it should be executed.
Packages:
CactusNeedleSharp— managed API, native interop, artifact management, and worker-pool client.CactusNeedleSharp.Worker— optional local .NET tool used for concurrent conversation isolation.
Quick start
using CactusNeedleSharp;
await using var needle = await NeedleClient.CreateAsync();
var weather = NeedleTool.FromJson("""
{
"name": "get_weather",
"description": "Get the current weather",
"parameters": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}
""");
var result = await needle.CompileAsync("What's the weather in Budapest?", [weather]);
if (result.IsConfident(0.80))
foreach (var call in result.Calls)
Console.WriteLine($"{call.Name}: {call.Arguments}");
The first call downloads the third-party Needle 2 platform runtime from the official Cactus Compute distribution into a separate local cache. The runtime wheel size and SHA-256 are pinned, and a manifest protects subsequent offline reuse. The runtime is not embedded in the NuGet package. Set Offline = true after the artifact is present, or provide NativeLibraryPath/upstream NEEDLE_LIB_PATH for air-gapped use. Set ExplicitNativeLibraryVersion when you know the version of a custom library; otherwise runtime reporting uses unknown instead of assuming the bundled version. No telemetry is collected.
Model-dependent tests are isolated in CactusNeedleSharp.IntegrationTests and run only when NEEDLE_RUN_INTEGRATION_TESTS=1; ordinary unit tests never download artifacts. BenchmarkDotNet benchmarks are kept separate from tests so cold initialization is not reported as warm inference throughput.
Release packaging is audited in CI: the package license, README, license and notice files are verified, and packaging fails if model weights or native Needle runtime binaries enter the NuGet archive unexpectedly.
Sessions and extraction
await using var session = await needle.CreateSessionAsync([weather]);
var first = await session.CompleteAsync("Weather in Budapest");
var next = await session.CompleteAsync("{\"temperature_c\": 22}");
await session.ResetAsync();
var invoice = await needle.ExtractAsync<Invoice>("Invoice from Acme Corp for $1,200.");
record Invoice(string Vendor, decimal Total);
Needle's confirmed ABI is process-global, so the in-process transport allows one live session per process and serializes calls within it. See the runtime investigation.
For concurrent, conversation-isolated workloads, use the bounded worker pool. Each active conversation exclusively leases one Needle child process; healthy base-model workers are reset and reused:
using CactusNeedleSharp.Worker;
await using var pool = new NeedleWorkerPool(new()
{
MaximumWorkers = 4,
MaximumQueueLength = 100,
QueueTimeout = TimeSpan.FromSeconds(10)
});
await pool.WarmAsync(2);
await using var conversation = await pool.CreateSessionAsync(tools);
var decision = await conversation.CompleteAsync(userIntent);
// The pool implements the same one-shot contracts as NeedleClient.
IToolCallCompiler isolated = pool;
var oneShot = await isolated.CompileAsync(userIntent, tools);
Worker auto-discovery checks the application directory; WorkerPath remains available for explicit deployment and local-tool configurations. Reference the CactusNeedleSharp.Worker project, deploy its build output alongside the application, or install the CactusNeedleSharp.Worker local .NET tool. See conversation-isolated worker pools.
Dependency injection and typed outcomes
services.AddCactusNeedleSharp(new NeedleOptions { Offline = true });
services.AddCactusNeedleSharpWorkerPool(new() { MaximumWorkers = 4 });
var outcome = result.GetOutcome(new() { MinimumConfidence = .80 });
var arguments = result.Calls[0].DeserializeArguments<WeatherArguments>();
Outcomes distinguish Success, NoCall, LowConfidence, and Failed; typed argument deserialization reports a NeedleProtocolException instead of leaking raw JSON errors.
IsConfident and GetOutcome apply the same threshold rule: a missing model confidence is treated as low confidence, and thresholds must be finite values from 0 through 1. Per-call MaxNewTokens overrides must be positive. Typed tools retain the serializer contract used to generate their schema, and calls are checked against the typed tool name before deserialization.
Generated schemas follow the selected System.Text.Json contract, including resolved property names, ignored members, enum representation, and string-keyed dictionaries as JSON objects. Typed extraction also accepts JsonTypeInfo<T> through IStructuredExtractor; set NeedleExtractionOptions.NestedTypeResolver when that schema references other source-generated types. Tools and native text are validated before a request crosses the native or worker boundary; duplicate tool names and embedded NUL characters are rejected.
Worker pools apply admission checks to both demand-driven creation and WarmAsync. Pool disposal waits for an in-progress worker start and rejects a worker that loses the shutdown race, while failed initialization returns its capacity exactly once. The pool uses a bounded queue and lazily expires idle workers when they are checked out.
To run the ordinary test suite, use dotnet test CactusNeedleSharp.slnx --no-restore. The integration tests are intentionally skipped unless NEEDLE_RUN_INTEGRATION_TESTS=1; when enabled, set NEEDLE_EXPECTED_ARCHITECTURE, NEEDLE_TEST_CACHE_DIRECTORY, and (for the pool test) NEEDLE_WORKER_PATH as described by the test project.
Add tools to a text-only model
Text-only / weak-tool LLM
│ natural-language intent
▼
CactusNeedleSharp
│ schema-constrained call
▼
Tool executor
Needle allows tool selection and schema-constrained argument generation to be separated from the reasoning model. It does not make every model a reliable autonomous agent.
Security
The package never executes generated calls. Schema validity != semantic correctness. Apply authorization, policy checks, business/domain validation, confidence thresholds, and confirmation for destructive actions before execution.
Upstream project and attribution
Needle 2 is developed by the Cactus Compute team.
CactusNeedleSharp only provides the .NET integration layer. It does not claim authorship of the Needle model, model architecture, training work, model weights, or Cactus runtime.
Please visit the upstream distributions for the authoritative documentation, models, licenses, research, authors, and academic citation:
License
CactusNeedleSharp source code is licensed under the Apache License 2.0.
Needle 2, Cactus runtime components, model weights, and other upstream Cactus Compute artifacts retain their respective upstream licenses and copyright notices.
See THIRD_PARTY_NOTICES.md and the official Cactus Compute distributions for details.
Disclaimer
CactusNeedleSharp is an independent open-source project.
It is not an official Cactus Compute product and is not affiliated with, sponsored by, or endorsed by Cactus Compute.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.2.0 | 94 | 9/13/2026 |
| 0.1.0 | 94 | 9/12/2026 |
| 0.1.0-alpha.1 | 97 | 8/20/2026 |