2 views
cactus-compute/needle
Automation foundation model for tiny devices: 2-bit, 8-29 MB, tool calls, structured extraction and embeddings on phones, wearables, smart homes, robots, cars and microcontrollers.
Python★ 11,677+234 that day#11 on trending
B70.2/100
Duplication88
1.1% in python, bash, javascript, perlDead code68
4.5%Complexity58
43.5% The score is jscpd's own --health model: markup, data and text left out, tests kept. The numbers below are the trending scan's.
1.5%duplicated code · 95 of 6,342 lines
7clones in code
33code files of 66 scanned
1.34%duplicated over all files · 12 clones
Most complex files
- needle/model/architecture.py240 cx
- needle/__init__.py194 cx
- needle/model/finetune.py124 cx
- needle/model/export.py116 cx
- needle/playground/app.js82 cx
- needle/agent/tools.py75 cx
- needle/_worker.py59 cx
- needle/model/quantize.py59 cx
- tests/test_weights.py53 cx
- needle/cli.py51 cx
Dead code 4.52% unused · 13 findings
- needle/playground/app.jsunused-file
- needle/model/architecture.py:_parameter_pathunused-symbol
- needle/model/run.py:_step_statsunused-symbol
- needle/model/tokenizer.py:TOOLS_END_IDunused-export
- needle/model/tokenizer.py:TOOLS_START_IDunused-export
- needle/model/tokenizer.py:TOOL_CALL_END_IDunused-export
- needle/model/tokenizer.py:TOOL_CALL_START_IDunused-export
- needle/model/tokenizer.py:IM_END_IDunused-export
- needle/model/tokenizer.py:IM_START_IDunused-export
- needle/model/tokenizer.py:THINK_END_IDunused-export
The code number leaves out tests, fixtures, docs, examples, data files, styles, translations and vendored code, and 1 generated file: needle/playground/app.js.
Largest clones in the code
- 16 lines in 6 placespython86 tokensneedle/environments/data_capture.py:117–132needle/environments/kitchen_appliance.py:106–121needle/environments/media_player.py:89–104needle/environments/productivity.py:118–133needle/environments/smart_home.py:124–139and 1 more
117 {'query': 'log my weight of 78.4 kg and 350 ml of water', 'calls': [{'name': 'log_weight', 'arguments': {'weight_kg': 78.4}}, {'name': 'log_water_intake', … 118] 119 120 121def run_tests(min_confidence=0.0, verbose=True): 122 return _harness.run_tests(sys.modules[__name__], min_confidence, verbose) 123 124 125def __getattr__(name): 126 if name == "agent":First 10 of 16 lines.
- 8 lines in 2 placespython76 tokens
111if generation >= 3: 112 lib.needle_embed.argtypes = [ 113 ctypes.c_char_p, ctypes.POINTER(ctypes.c_float), ctypes.c_int] 114 lib.needle_embed.restype = ctypes.c_int 115lib.needle_reset.argtypes = [] 116lib.needle_reset.restype = None 117lib.needle_load.argtypes = [ctypes.c_char_p, ctypes.c_uint64] 118lib.needle_load.restype = ctypes.c_int - 7 lines in 2 placespython62 tokens
105lib = ctypes.CDLL(_library_path(generation)) 106lib.needle_init.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p] 107lib.needle_init.restype = ctypes.c_int 108lib.needle_complete.argtypes = [ 109 ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_int] 110lib.needle_complete.restype = ctypes.c_int 111if generation >= 3:51lib = ctypes.CDLL(path) 52lib.needle_init.argtypes = [ctypes.c_char_p, ctypes.c_char_p, 53 ctypes.c_char_p] 54lib.needle_init.restype = ctypes.c_int 55lib.needle_complete.argtypes = [ctypes.c_char_p, ctypes.c_int, 56 ctypes.c_char_p, ctypes.c_int] 57lib.needle_complete.restype = ctypes.c_int 58if int(generation) >= 3:
Largest clones over all files, tests and data included
- 16 lines in 6 placespython86 tokensneedle/environments/data_capture.py:117–132needle/environments/kitchen_appliance.py:106–121needle/environments/media_player.py:89–104needle/environments/productivity.py:118–133needle/environments/smart_home.py:124–139and 1 more
117 {'query': 'log my weight of 78.4 kg and 350 ml of water', 'calls': [{'name': 'log_weight', 'arguments': {'weight_kg': 78.4}}, {'name': 'log_water_intake', … 118] 119 120 121def run_tests(min_confidence=0.0, verbose=True): 122 return _harness.run_tests(sys.modules[__name__], min_confidence, verbose) 123 124 125def __getattr__(name): 126 if name == "agent":First 10 of 16 lines.
- 11 lines in 2 placesmarkupmarkup268 tokens
231<text x="40" y="70" font-family="Inter, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="20" font-weight="600" fill="#e8e6df">SNIPS gold</te… 232<text x="40" y="88" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="11" fill="#85827a">field F1 · 700 rows · F1 (%)</text> 233<line x1="382.5" y1="102" x2="382.5" y2="366" stroke="#232326" stroke-width="1"/> 234<text x="382.5" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">25</text> 235<line x1="515.0" y1="102" x2="515.0" y2="366" stroke="#232326" stroke-width="1"/> 236<text x="515.0" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">50</text> 237<line x1="647.5" y1="102" x2="647.5" y2="366" stroke="#232326" stroke-width="1"/> 238<text x="647.5" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">75</text> 239<line x1="780.0" y1="102" x2="780.0" y2="366" stroke="#232326" stroke-width="1"/> 240<text x="780.0" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">100</text>First 10 of 11 lines.
- 10 lines in 2 placesmarkupmarkup237 tokens
179<text x="40" y="88" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="11" fill="#85827a">field F1 · 1,813 turns · F1 (%)</text> 180<line x1="382.5" y1="102" x2="382.5" y2="366" stroke="#232326" stroke-width="1"/> 181<text x="382.5" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">25</text> 182<line x1="515.0" y1="102" x2="515.0" y2="366" stroke="#232326" stroke-width="1"/> 183<text x="515.0" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">50</text> 184<line x1="647.5" y1="102" x2="647.5" y2="366" stroke="#232326" stroke-width="1"/> 185<text x="647.5" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">75</text> 186<line x1="780.0" y1="102" x2="780.0" y2="366" stroke="#232326" stroke-width="1"/> 187<text x="780.0" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">100</text> 188<line x1="674.0" y1="96" x2="674.0" y2="370" stroke="#e8593d" stroke-width="1.2" stroke-dasharray="1 5" stroke-linecap="round" opacity="0.8"/>232<text x="40" y="88" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="11" fill="#85827a">field F1 · 700 rows · F1 (%)</text> 233<line x1="382.5" y1="102" x2="382.5" y2="366" stroke="#232326" stroke-width="1"/> 234<text x="382.5" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">25</text> 235<line x1="515.0" y1="102" x2="515.0" y2="366" stroke="#232326" stroke-width="1"/> 236<text x="515.0" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">50</text> 237<line x1="647.5" y1="102" x2="647.5" y2="366" stroke="#232326" stroke-width="1"/> 238<text x="647.5" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">75</text> 239<line x1="780.0" y1="102" x2="780.0" y2="366" stroke="#232326" stroke-width="1"/> 240<text x="780.0" y="384" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" font-size="10" fill="#4a4844">100</text> 241<line x1="617.8" y1="96" x2="617.8" y2="370" stroke="#e8593d" stroke-width="1.2" stroke-dasharray="1 5" stroke-linecap="round" opacity="0.8"/> - 10 lines in 2 placesmarkupmarkup235 tokens
- 8 lines in 2 placespython76 tokens
By format, code only
| Format | Files | Lines | Clones | Duplicated lines | Duplication |
|---|---|---|---|---|---|
| python | 22 | 5,483 | 7 | 95 | 1.73% |
| bash | 10 | 685 | 0 | 0 | 0% |
| perl | 1 | 174 | 0 | 0 | 0% |
By format, all files
| Format | Files | Lines | Clones | Duplicated lines | Duplication |
|---|---|---|---|---|---|
| python | 40 | 7,718 | 8 | 105 | 1.36% |
| markup | 6 | 654 | 3 | 31 | 4.74% |
| css | 1 | 513 | 1 | 7 | 1.36% |
| bash | 11 | 692 | 0 | 0 | 0% |
| javascript | 1 | 331 | 0 | 0 | 0% |
| txt | 1 | 226 | 0 | 0 | 0% |
| perl | 1 | 174 | 0 | 0 | 0% |
| yaml | 2 | 174 | 0 | 0 | 0% |
| markdown | 1 | 101 | 0 | 0 | 0% |
| toml | 1 | 46 | 0 | 0 | 0% |
Trending appearances
| Day | Rank | Stars | Files | Lines | Clones | All files | Code | Health | Commit |
|---|---|---|---|---|---|---|---|---|---|
| Sep 20, 2026 | #11 | 11,677 (+234) | 66 | 10,637 | 12 | 1.34% | 1.5% | B 70.2 | fc5bae0 |
Want this for your own project? Install jscpd and run jscpd ., or measure it the way the baselines were measured.