Call LLMs straight from Excel cells — and let an agent edit your sheet — across Excel for Mac, Windows, Web, and iPad. Bring your own provider (OpenAI, Mistral, Nebius, Scaleway, OpenRouter, or local Ollama).
▶ Live: https://crispstrobe.github.io/ExcelLLMAddin/ — install by sideloading
manifest.xml (see
install steps).
There are two editions in this repo:
| Edition | Where | Best for |
|---|---|---|
Office.js add-in (officejs/) |
Mac · Windows · Web · iPad | store/AppSource, the widest reach, streaming |
VBA .xlam (repo root .bas) |
Mac · Windows | fully offline / air-gapped, single-file install |
Both have the function set and the sheet-editing agent. The .xlam runs with no
hosting and no internet (pair it with local Ollama); the Office.js edition adds
Web/iPad, AppSource, and STREAM.
Worksheet functions (namespace LLM):
| Function | Purpose |
|---|---|
=LLM.PROMPT(text, [provider], [model]) |
Ask an LLM from a cell |
=LLM.STREAM(text, …) |
Like PROMPT, streamed into the cell live |
=LLM.CLASSIFY(text, categories) |
Pick one label from a range/list |
=LLM.EXTRACT(text, instruction) |
Pull a single value out of text |
=LLM.FIELDS(text, fields) |
Extract many fields into a row (text → table) |
=LLM.TRANSLATE(text, language) |
Translate a cell |
=LLM.SUMMARIZE(text, [maxWords]) |
Summarize a cell |
=LLM.SENTIMENT(text) |
Positive / Neutral / Negative |
=LLM.TAG(text, categories) |
Multi-label: all labels that apply |
=LLM.LIST(prompt, [count]) |
Generate a list, spilled down a column |
=LLM.TABLE(prompt) |
Generate a 2D table, spilled as a grid |
=LLM.FILL(examples, inputs) |
Infer a pattern from example pairs, apply down a column |
=LLM.EDIT(text, [instruction]) |
Rewrite / fix grammar |
=LLM.FORMULA(description) |
Write an Excel formula from plain English |
=LLM.EXPLAIN(formula) |
Explain a formula (pair with FORMULATEXT) |
=LLM.VISION(image, [question]) |
Ask about an image (URL or data URI) |
=LLM.IMAGE(prompt, [w], [h]) |
Generate an image; wrap in =IMAGE(...) to show it |
=LLM.ASK(question, context) |
Answer a question using a range as context |
=LLM.SIMILARITY(a, b, [model]) |
Semantic similarity (0–1) via embeddings |
=LLM.RECALL(query, range, [k]) |
Semantic search: top rows in a range by meaning |
=LLM.MAP(range, instruction) |
Apply an instruction to every cell (batched) |
=LLM.LIST_MODELS([provider]) · =LLM.CONFIG() |
List models · show config |
Plus an Agent: describe a change in plain English in the task pane and the model reads/edits your workbook (ranges, formulas, formatting, sheets) via tool-calling — with approve-before-apply by default. Its toolset can be extended with remote MCP servers.
Use it (any user): sideload the hosted manifest — see officejs/PUBLISHING.md for Mac / org-deployment / AppSource.
Develop it:
cd officejs
npm install
npm start # builds, starts the https dev-server, sideloads into Excel
npm test # 160+ unit/functional tests (~99% line coverage), no Excel neededDetails, the browser dev-harness, and the CORS/proxy notes are in officejs/README.md.
Drop these into cells (Office.js namespace shown; the .xlam uses the same names
without the LLM. prefix, e.g. =CLASSIFY(...)):
| Goal | Formula |
|---|---|
| Tag each support ticket | =LLM.CLASSIFY(A2, {"Bug";"Billing";"Feature"}) |
| Split freeform text into columns | =LLM.FIELDS(A2, "name, email, company") (spills across) |
| Translate a whole column at once | =LLM.MAP(A2:A200, "translate to German") (batched) |
| Summarize to ~20 words | =LLM.SUMMARIZE(A2, 20) |
| Score sentiment | =LLM.SENTIMENT(A2) |
| Semantic match against a reference | =LLM.SIMILARITY(A2, $B$1) |
| Answer from a range of context | =LLM.ASK("what's the refund policy?", D2:D50) |
| Generate a list down a column | =LLM.LIST("EU capital cities", 10) |
| Generate a whole table | =LLM.TABLE("5 largest EU countries with population") |
| Fill by example (learn from 2-3 rows) | =LLM.FILL(A2:B4, C2:C100) |
| Write a formula from words | =LLM.FORMULA("sum col B where A > 100") |
| Explain a formula | =LLM.EXPLAIN(FORMULATEXT(D2)) |
| Ask about an image | =LLM.VISION("https://…/chart.png", "what's the trend?") |
| Generate an image into a cell | =IMAGE(LLM.IMAGE("a red bicycle, studio photo")) |
Agent (task pane, plain English): "In D1 put the sum of B2:B10, then bold anything over 100" · "add a column classifying each row of my selection as high/low". Writes are queued for one-click Apply unless you opt into auto-apply.
OpenAI · Mistral · Nebius · Scaleway · OpenRouter · Groq · Together · Cerebras · Google Gemini · Cohere · Hugging Face · Requesty · Ollama (local). OpenRouter,
Nebius, and local Ollama work directly from the browser; others use the optional
key-custody proxy (officejs/proxy/worker.js).
Both editions read the catalog from one source of truth,
shared/providers.json; the Office.js tables are
generated from it (npm run gen:providers) and CI fails on drift, so a provider
URL can't go stale in one edition only.
The VBA add-in (repo root .bas/.cls) is fully self-contained and offline —
no hosting, no web server. It has near-parity with the Office.js edition:
- Functions:
=PROMPT,=CLASSIFY,=EXTRACT,=TRANSLATE,=SUMMARIZE,=SENTIMENT,=ASK,=LIST,=FIELDS,=MAP,=SIMILARITY,=RECALL,=TAG,=EDIT,=FORMULA,=EXPLAIN,=LLMTABLE,=FILL,=VISION,=IMAGE_GEN,=LIST_MODELS,=LLM_CONFIG(modLLMFunctions.bas,modTasks.bas). (LLMTABLEis the Office.jsTABLE, renamed to avoid Excel's legacy Data-Table function.) - Agent (
modAgent.bas) — run theRunAgentmacro; the model edits the sheet via nativeRangetools (read, write, formulas, formatting, sheets, charts) with approve-before-apply. With local Ollama, this is a fully air-gapped AI that edits your workbook. - MCP (
modMcp.bas) — runSetMcpServerto add a remote MCP server's tools to the agent (best-effort JSON-RPC over HTTP; targets stateless servers). - Providers: the same catalog as the Office.js edition — OpenAI, Mistral, Nebius, Scaleway, OpenRouter, Groq, Together, Cerebras, Gemini, Cohere, Hugging Face, Requesty, and local Ollama. Configure the added cloud ones via the settings menu's C option (they share one OpenAI-compatible code path).
- Solid plumbing: injected
IHttpClient(WinHTTP/curl), real JSON (vendored VBA-JSON), UTF-8, a response cache, batched embeddings for=RECALL(one request for all candidates instead of one per row), and aRunAllTestsself-test harness. - Image generation:
=IMAGE_GEN("...")returns a URL (pair with=IMAGE()), or run theInsertAIImagemacro to drop the picture at the active cell. Set the key once withSetImageKey. (Black Forest Labs / FLUX; x-key auth.) - Office.js-only:
STREAM(VBA UDFs are synchronous -- no live cell updates).
Build: pwsh tools/Build-Addin.ps1 on Windows+Excel, or import the modules in
the VBA editor and Save As .xlam (Excel is required to compile VBA — it can't be
built on Mac or GitHub-hosted CI). Install offline: installer/mac-xlam/
builds a .pkg that drops the .xlam into Excel's add-ins folder. See
installer/README.md.
AGPL-3.0.