agentsclimarketplace

Muninn embed text

Skill neozenith/sqlite-muninn/skills/muninn-embed-text

Generates text embeddings inside SQLite via muninn_embed() backed by local GGUF models (BERT, MiniLM, nomic-embed-text, BGE-M3, Qwen3-Embedding) through llama.cpp with Metal GPU acceleration on macOS. Covers muninn_embed_model registration, the temp.muninn_models virtual table, composing with hnsw_index for semantic search, and auto-embed TEMP triggers. Use when the user mentions "text embedding", "semantic search", "sentence embedding", "muninn_embed", "GGUF embedding model", "MiniLM", "nomic-embed", "BGE-M3", "Qwen3 embedding", "embed model in SQLite", "text-in semantic-search-out", or wants to embed text directly in SQL.From its SKILL.md

Install
npx -y skills add neozenith/sqlite-muninn --skill muninn-embed-text

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

6.6 KB, as published. Nobody here has run it

muninn-embed-text — GGUF text embeddings in SQLite

muninn_embed() runs llama.cpp under the hood to produce L2-normalized float32 embeddings from raw text, in SQL. Output is the exact blob format accepted by hnsw_index (see muninn-vector-search).

Step 1 — Download a GGUF embedding model

mkdir -p models
curl -L -o models/all-MiniLM-L6-v2.Q8_0.gguf \
  https://huggingface.co/leliuga/all-MiniLM-L6-v2-GGUF/resolve/main/all-MiniLM-L6-v2.Q8_0.gguf
ModelDimsFileUse case
all-MiniLM-L6-v2 Q8_038436 MBFast default for English
nomic-embed-text-v1.5 Q4_K_M76884 MBLong context, multilingual
BGE-M3 Q4_K_M1024438 MB100+ languages
Qwen3-Embedding-8B Q4_K_M40964.7 GBSOTA retrieval quality

Step 2 — Register the model (session-scoped)

.load ./muninn

INSERT INTO temp.muninn_models(name, model)
  SELECT 'MiniLM', muninn_embed_model('models/all-MiniLM-L6-v2.Q8_0.gguf');

SELECT name, dim FROM temp.muninn_models;
name    dim
------  ---
MiniLM  384

Pooling is read from the GGUF metadata (BERT → MEAN, Qwen3 → LAST) — never hardcode. Models are registered per-connection and in temp.*; re-register after reconnecting.

Step 3 — Embed text inline in SQL

SELECT length(muninn_embed('MiniLM', 'hello, world')) AS bytes;
bytes
-----
1536        -- 384 floats × 4 bytes

muninn_embed(model_name, text) returns a BLOB with byte length 4 × dim, already L2-normalized. That blob goes directly into hnsw_index or into any other column.

End-to-end — semantic search pipeline

.load ./muninn

INSERT INTO temp.muninn_models(name, model)
  SELECT 'MiniLM', muninn_embed_model('models/all-MiniLM-L6-v2.Q8_0.gguf');

CREATE TABLE documents (id INTEGER PRIMARY KEY, content TEXT);
INSERT INTO documents(content) VALUES
  ('The quick brown fox jumps over the lazy dog'),
  ('A fast runner sprints across the field'),
  ('SQLite is a lightweight embedded database'),
  ('Vector search finds similar items by distance');

CREATE VIRTUAL TABLE docs USING hnsw_index(dimensions=384, metric='cosine');

INSERT INTO docs(rowid, vector)
  SELECT id, muninn_embed('MiniLM', content) FROM documents;

SELECT d.content, round(v.distance, 4) AS dist
  FROM docs v JOIN documents d ON d.id = v.rowid
  WHERE v.vector MATCH muninn_embed('MiniLM', 'fast animal') AND k = 2;
content                                        dist
---------------------------------------------  ------
A fast runner sprints across the field         0.3881
The quick brown fox jumps over the lazy dog    0.5217

Auto-embed triggers

Use TEMP triggers only — persistent triggers fail when the DB is reopened without the extension.

CREATE TEMP TRIGGER auto_embed AFTER INSERT ON documents
BEGIN
  INSERT INTO docs(rowid, vector)
    VALUES (NEW.id, muninn_embed('MiniLM', NEW.content));
END;

CREATE TEMP TRIGGER auto_reembed AFTER UPDATE OF content ON documents
BEGIN
  DELETE FROM docs WHERE rowid = NEW.id;
  INSERT INTO docs(rowid, vector)
    VALUES (NEW.id, muninn_embed('MiniLM', NEW.content));
END;

-- Now text goes in, embeddings materialize automatically
INSERT INTO documents(content) VALUES ('Neural networks learn from data');

Runtime variants

Python

import sqlite3
import sqlite_muninn

db = sqlite3.connect(":memory:")
db.enable_load_extension(True)
sqlite_muninn.load(db)
db.enable_load_extension(False)

db.execute("""
    INSERT INTO temp.muninn_models(name, model)
    SELECT 'MiniLM', muninn_embed_model('models/all-MiniLM-L6-v2.Q8_0.gguf')
""")

# Embed and retrieve as bytes
blob = db.execute("SELECT muninn_embed('MiniLM', ?)", ('hello',)).fetchone()[0]
print(len(blob))   # 1536

Node.js

import Database from "better-sqlite3";
import { load } from "sqlite-muninn";

const db = new Database(":memory:");
load(db);

db.exec(`
  INSERT INTO temp.muninn_models(name, model)
  SELECT 'MiniLM', muninn_embed_model('models/all-MiniLM-L6-v2.Q8_0.gguf');
`);

const blob = db.prepare("SELECT muninn_embed('MiniLM', ?) AS v")
               .get("hello world").v;
console.log(blob.byteLength);   // 1536

WASM

// Model file must be present in the virtual filesystem first
sqlite3.FS.writeFile("/models/miniLM.gguf", gguf_bytes);
db.exec(`
  INSERT INTO temp.muninn_models(name, model)
  SELECT 'MiniLM', muninn_embed_model('/models/miniLM.gguf');
`);
const blob = db.selectValue("SELECT muninn_embed('MiniLM', 'hello')");

WASM runs CPU-only — expect 5–10× slower embedding vs. Metal on macOS.

Performance notes

  • On macOS, embeddings run on Metal GPU by default (MUNINN_GPU_LAYERS=99). Single-text throughput ≈ 5k embeddings/sec for MiniLM on M1.
  • No batched variant exists — muninn_embed takes one text at a time. For throughput, open multiple connections and embed in parallel.
  • muninn_token_count('MiniLM', text) is cheaper than generating an embedding when you only need to chunk.

Related functions

FunctionReturnsPurpose
muninn_embed_model(path, n_ctx?)opaque handleLoad a GGUF file — only useful as INSERT value into temp.muninn_models
muninn_embed(name, text)BLOBEmbed text with a registered model
muninn_model_dim(name)INTEGERQuery dimension of a registered model
muninn_tokenize(name, text)JSON arrayInspect tokenization
muninn_token_count(name, text)INTEGERCount tokens cheaply

See also

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.