Needle Router
Classify a request into a branch, without spending GPU on an LLM
- index
- route
- confidence
- gated
- info
Every serious workflow eventually asks the same question: which branch should this run? You've got a txt2img path, an img2img path, an inpaint path, an upscale path, and some human text saying what they want. Needle Router's whole job is deciding - it reads a request, classifies it into one of the routes you define, and hands you an index you can plug into a switch. "remove the car from this photo" → inpaint → index 2, wired straight into an Impact Pack switch. Zero VRAM, ~0.16 s, and it keeps the decision inside the graph instead of shipping the text out to an API.
The mechanism is the interesting part. Each route is declared as its own tool - one tool per route, not one enum-valued field. That's not a stylistic choice; the README documents that the enum form scored 0/6 on a test set while the one-tool-per-route form scored 4/6. Needle 2 is trained to select a tool, so you build your routes in the shape it was trained on. The output is an index (INT, for the switch), the winning route name (STRING), the confidence (FLOAT), and gated (BOOLEAN, true if confidence fell below your threshold).
The inputs that matter
- routes - one per line,
name: description. The default is a sensible four-route set: txt2img, img2img, inpaint, upscale. Keep the list short - tools are pinned in the 256-token window, and a 30-route list will make every route blur together. - threshold - the confidence gate, 0 to 1. Below this, the fallback wins. Default is 0, which disables the gate.
- fallback_index - which route to return when the gate triggers. Default 0.
- text - the request to classify. Optional system for environment facts.
Outputs beyond the switch-fodder: confidence, gated, and info (a STRING with the reasoning). gated is genuinely useful for a display or a log line so you can see when a request bounced to fallback.
The honest limits - read this before trusting it
This is where the README does its best work, and where people who skip it get burned. Measured on the built-in routes: 4/6 correct. And the failure pattern is the unsettling part - wrong answers came back with middling confidence (0.65–0.68) while correct ones sometimes came back at 0.00. The confidence score is a backstop against nonsense input, not a correctness signal. The README's advice is explicit: leave threshold at 0 unless you have measured your own routes. Set it to 0.7 because it "feels safer" and you'll be silently rerouting correct classifications to fallback. Build the routes, test them on your actual request vocabulary, and only then decide if a gate earns its place.
Also worth knowing: finetuned .cact weights report no confidence at all, so the gate is meaningless if you load custom weights. And the model is English-only in practice - a German request produced no call where the English equivalent scored 0.996.
Wiring it in
The output is an INT index, and the README's own example is an Impact Pack switch. Any switch that selects by index works the same way: feed index to the selector, wire each branch into a switch input, and the graph routes itself. ComfyUI's plumbing layer is built exactly for this - index switches, * inputs, and fallback logic - and the KB's node-plumbing essay is the background reading if you want to understand the switch side properly.
Install
Same pack, same steps: ComfyUI Manager, search ComfyUI Needle 2, or git clone https://github.com/DenRakEiw/Comfyui_Needle2 + pip install cactus-needle, then restart. First run downloads the 14 MB CPU engine into ~/.cache/cactus-needle/. Don't rename the folder to needle (engine package collision), and watch for the Windows Smart App Control [WinError 4551] block on the unsigned DLL.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | — | |
| routes | STRING | txt2img: generate a brand new image from a description img2img: change or restyle an image the user already has inpaint: replace or remove part of an existing image upscale: enlarge an image or add detail without changing the content | One route per line, 'name: description'. Tools are pinned in the 256-token window, so keep the list short. |
| threshold | FLOAT | 0.000–1 | Below this confidence the fallback wins. 0 disables the gate. Finetuned weights report no confidence at all. |
| fallback_index | INT | 00–63 | — |
| systemopt | STRING | — |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| index | INT | — |
| route | STRING | — |
| confidence | FLOAT | — |
| gated | BOOLEAN | — |
| info | STRING | — |