# Loom Spark Harness The agent harness for [Loom Spark](https://huggingface.co/TextileLabs/loom-spark) (Textile Labs). Loom Spark is a ~7.6M-parameter model trained to be humble, self-aware, and curious instead of encyclopedic. Its one real superpower is forming clean search queries — **this harness is what turns that into actual internet access.** It implements the tool protocol the model was trained on: ``` | mode header, set by the harness each session query emitted by the model; harness runs a real search text injected by the harness; model then summarizes ``` With tools off, the model never emits lookup tags (banned at the logits level and string-stripped as a safety net). With tools on, the harness owns the `` slot entirely — the model cannot hallucinate one. ## Install ```bash pip install . # from this folder (or the harness/ folder of the HF repo) ``` Works on Python 3.9 through 3.13 (CPU torch wheels exist for all of them). Optional: `pip install ".[logo]"` adds Pillow so the terminal banner renders the Textile Labs avatar in truecolor blocks; without it you get a clean ASCII mark instead. ## Terminal chat ```bash loom-chat # auto-finds a local export dir or pulls # TextileLabs/loom-spark from the hub loom-chat --offline # start with tools off loom-chat --backend duckduckgo # search backend: mock | duckduckgo loom-chat --model path/or/org-name loom-chat --plain # no colors / artwork ``` In-chat commands: `/online` `/offline` `/backend NAME` `/reset` `/quit`. ## Web GUI ```bash loom-web --port 7860 # then open http://localhost:7860 ``` Local-only chat page (stdlib HTTP server) with a tools-on/off switch, token streaming, and a live feed of internet lookups. ## Model resolution `--model` wins; else `$LOOM_MODEL`; else an `export/loom-spark-hf` directory next to the package or in the cwd; else the hub id `TextileLabs/loom-spark`. Accepted values: HF export directory, `.pt` training checkpoint (needs the training repo importable), or any `org/name` hub id. ## Search backends | name | internet | notes | |---|---|---| | `mock` | no | canned curriculum-style results; demos & tests | | `duckduckgo` | yes | keyless scrape of DDG's HTML endpoint; stdlib only | A backend maps query → plain text, or `None` when unreachable — the model was trained to fall back gracefully on empty results. Add your own by subclassing `loomspark_harness.search.base.SearchBackend` (e.g. Brave/Serper with an API key) and registering it in `search/__init__.py`. The web GUI header and the CLI banner use `static/logo.png` (the Textile Labs founder's avatar). Replace that file to rebrand. ## Troubleshooting **Intel (x86_64) Macs:** PyTorch stopped shipping Intel-macOS wheels at 2.2.2, and the newest numpy/transformers are incompatible with it. Install era-matched pins instead of plain `pip install torch transformers`: ```bash pip install "numpy<2" "torch==2.2.2" "transformers<5" tokenizers pillow ``` ## Using the agent from Python ```python from loomspark_harness.loader import load_model_and_tokenizer from loomspark_harness.agent import LoomAgent from loomspark_harness.search import get_backend model, tok, block = load_model_and_tokenizer("TextileLabs/loom-spark") agent = LoomAgent(model, tok, backend=get_backend("duckduckgo"), online=True, block_size=block) print(agent.reply("what year did the Titanic sink?")["text"]) ``` `reply()` returns `{"text", "query", "result"}`; pass `on_event=` for a callback stream of `token` / `preamble` / `lookup` / `result` / `done` events (the web GUI is built on this). ## License MIT — see LICENSE.