curiosity

Curiosity Spark

Models on your hardware.
APIs you already use.

Run open language models on your own servers and call them with the OpenAI and Anthropic SDKs your code already uses, or from Curiosity Studio. Prompts, answers and models never leave your network.

Spark serves a model inside your network Inside a dashed boundary marked your network: an app with the OpenAI SDK, an agent with the Anthropic SDK and Curiosity Studio call Spark. Spark runs the model on your own hardware and streams the answer back word by word. Nothing crosses the boundary. YOUR NETWORKNOTHING LEAVES ITYour appOPENAI SDKYour agentANTHROPIC SDKCuriosity StudioOPENAI COMPATIBLESPARKOne portBoth APIsKeys and a logof every requestYOUR HARDWARECPU or GPUMODEL IN MEMORYqwen3THE ANSWER, STREAMED
Spark serves a model inside your network Inside a dashed boundary marked your network: an app with the OpenAI SDK, an agent with the Anthropic SDK and Curiosity Studio call Spark. Spark runs the model on your own hardware and streams the answer back word by word. Nothing crosses the boundary. YOUR NETWORKNOTHING LEAVES ITYour appOPENAIYour agentANTHROPICCuriosity StudioOPENAISPARKOne port, both APIsYOUR HARDWARE · CPU OR GPUqwen3 in memoryTHE ANSWER, STREAMED

04 · Nothing leaves your network

APIs OpenAI and Anthropic Models Open models from Hugging Face Runs on CPU or NVIDIA GPU Console Models, keys, request log

What it does

The model endpoint your code already knows how to call

Open models on your own machines, behind the same APIs as the cloud. Your prompts stay with you.

01

No code to rewrite

OpenAI and Anthropic SDKs work as they are: change the address, keep the code. Streaming, tool calls, reasoning and structured output included.

02

Your data stays inside

Prompts, answers and model weights never leave your network. There is no provider account to sign up for.

03

Uses the hardware you have

Spark fits each model to the memory it finds, CPU or GPU, and makes room by unloading models nobody is using.

04

Every model behind one address

Chat, vision and embedding models side by side. Name a model in the request, and Spark loads it if it is not running yet.

Streaming

Streamed as it is written

Your client gets each piece of the answer as it is written, exactly as it would from a cloud API. Pick a request to watch it arrive.

Pick a request

What the client assembles

1. Confirm the isolation valves are open. 2. Look for leaks at the seal. 3. Read the last maintenance log entry.

Example answers, shortened to the text field.

Terminal · a streamed response
 curl http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer sk-spark-…" -H "Content-Type: application/json" \
  -d '{"model": "smollm2-135m-instruct-q8_0", "stream": true, "messages": [{"role": "user", "content": "List three checks before a pump restart."}]}'
data: {"choices":[{"delta":{"content":"1."}}]}
data: {"choices":[{"delta":{"content":" Confirm"}}]}
data: {"choices":[{"delta":{"content":" the"}}]}
data: {"choices":[{"delta":{"content":" isolation"}}]}
data: {"choices":[{"delta":{"content":" valves"}}]}
data: {"choices":[{"delta":{"content":" are"}}]}
data: {"choices":[{"delta":{"content":" open."}}]}
data: {"choices":[{"delta":{"content":" 2."}}]}
data: {"choices":[{"delta":{"content":" Look"}}]}
data: {"choices":[{"delta":{"content":" for"}}]}
data: {"choices":[{"delta":{"content":" leaks"}}]}
data: {"choices":[{"delta":{"content":" at"}}]}
data: {"choices":[{"delta":{"content":" the"}}]}
data: {"choices":[{"delta":{"content":" seal."}}]}
data: {"choices":[{"delta":{"content":" 3."}}]}
data: {"choices":[{"delta":{"content":" Read"}}]}
data: {"choices":[{"delta":{"content":" the"}}]}
data: {"choices":[{"delta":{"content":" last"}}]}
data: {"choices":[{"delta":{"content":" maintenance"}}]}
data: {"choices":[{"delta":{"content":" log"}}]}
data: {"choices":[{"delta":{"content":" entry."}}]}
data: {"choices":[{"delta":{},"finish_reason":"stop"}]}
data: [DONE]

Models

More models on the machines you already have

Find a model on Hugging Face from the console and download it. Spark works out where it fits, and makes room when it has to. Pick a step to stop the drawing and read it.

Models fitted into one machine’s memory A bar of 32 squares is the memory of one machine. Model A takes 12, model B 10. Model C needs 12 and only 10 are free, so Spark unloads model A, which had no recent requests, and model C loads in its place. ONE MACHINE · 32 GB1 SQUARE = 1 GBMODEL ANO REQUESTS LATELYMODEL BUNLOADEDMODEL C · NEEDS 12 GB10 GB FREEMODEL CWEIGHTSCACHEBUFFERSFREE
Models fitted into one machine’s memory A bar of 32 squares is the memory of one machine. Model A takes 12, model B 10. Model C needs 12 and only 10 are free, so Spark unloads model A, which had no recent requests, and model C loads in its place. ONE MACHINE · 32 GBMODEL C · NEEDS 12 GB, 10 FREEAA UNLOADEDCBWEIGHTSCACHEBUFFERSFREE
  1. 01

    A model loads where it fits

    Spark counts what a model needs before it starts it: the weights, the cache for the conversation, the working buffers.

  2. 02

    A second model loads beside it

    Two models, side by side on one machine, each answering its own requests.

  3. 03

    A third needs more than is free

    Model C asks for 12 GB and 10 GB are free. Spark does not start it to watch it fail.

  4. 04

    The idle model makes room

    Model A has had no requests for a while, so Spark unloads it. It loads again the next time someone asks for it.

  5. 05

    Model C runs

    It loads into the room made for it. A model too large for any machine is refused, with the arithmetic.

One endpoint

Every model your teams need, at one address

Give your applications one endpoint and a choice of models. Each request names the model it wants, and Spark takes care of the rest.

One Spark endpoint serving several models side by side One address on the left. Requests for a chat model, a vision model and an embedding model go to their own models and are answered side by side. A request for a fourth model, not yet loaded, loads it, and it answers too. ONE ADDRESSspark.example.comqwen3CHATsmolvlmVISIONminilmEMBEDDINGSgraniteLOADINGgraniteCHAT
One Spark endpoint serving several models side by side One address at the top. Requests for a chat model, a vision model and an embedding model go to their own models and are answered side by side. A request for a fourth model, not yet loaded, loads it, and it answers too. ONE ADDRESSspark.example.comqwen3CHATsmolvlmVISIONminilmEMBEDDINGSgraniteLOADINGgraniteCHAT
  1. 01

    One address for every model

    Chat, vision and embedding requests all go to the same endpoint. Each names the model it wants.

  2. 02

    Each request finds its model

    Spark sends every request to the model it named, wherever that model is loaded.

  3. 03

    Models answer side by side

    A chat model writes, a vision model describes an image, an embedding model returns vectors for search, all at once.

  4. 04

    Ask for a model that is not loaded

    Name any model in the library. Spark loads it on the first request.

  5. 05

    Ready, and it stays ready

    It answers, and stays loaded while it is used. When nobody needs it, it makes room for others.

And the rest

Everything around the model, built in

Keys, logs, caching and more machines come with the server, not as extra services.

Fast follow up questions

The next turn of a chat picks up where the last one ended, even after other conversations came in between.

Images and search

Vision models read images sent the way OpenAI or Anthropic clients send them. Embedding models serve semantic search.

Keys that keep nothing

Create a key with zero retention, and its requests are logged without the prompt or the answer.

Every request on record

Who asked, with which key, which model, how many tokens and how long it took, step by step.

More machines

Add machines and Spark routes each request to the one that has the model loaded.

Locked by default

Every call needs an API key unless you switch that off. Put your own HTTPS proxy in front for access beyond your network.

With Studio

Give Studio a model on your own hardware

Studio takes any OpenAI compatible endpoint as its model. Spark serves one, so the tools your teams build can run on weights that stay on your machines.

Read the Docs See Models

01

Run Spark

Install it on a machine with room for the model and start it with a password. The console is at localhost:8080.

02

Create an API key

In the console, under API keys. Spark’s endpoint is the address with /v1 on the end.

03

Add it to Studio

Add the endpoint and the key as an OpenAI compatible provider, and name the model as the console lists it, such as smollm2-135m-instruct-q8_0.

Install

An answer in a few minutes

One command to install, one to start. Everything is in the download.

macOS · Linux

01 · Install

Downloads the latest release, checks it and puts spark on your PATH.

Terminal
 curl -fsSL https://raw.githubusercontent.com/curiosity-ai/spark/refs/heads/main/install.sh | sh

02 · Start it

Start it with a password for the console, and a folder for its models.

Terminal
 SPARK_ADMIN_PASSWORD='choose-a-password' SPARK_STORAGE="$HOME/.curiosity/spark-data" spark

What you see

Example session · what the installer prints
 curl -fsSL https://raw.githubusercontent.com/curiosity-ai/spark/refs/heads/main/install.sh | shInstalling Spark (linux-x64)  downloading v26.10.6452: https://github.com/curiosity-ai/spark/releases/download/v26.10.6452/spark-26.10.6452-linux-x64.tar.gz  sha256 verified  installed /home/you/.curiosity/spark  launcher  /home/you/.curiosity/bin/spark  added /home/you/.curiosity/bin to PATH in /home/you/.bashrc Spark v26.10.6452 is installed.Open a new terminal, or run this one first:  export PATH="/home/you/.curiosity/bin:$PATH"Then start it with a management password (data and models go to ./storage unless SPARK_STORAGE says otherwise):  SPARK_ADMIN_PASSWORD='choose-a-password' SPARK_STORAGE="$HOME/.curiosity/spark-data" sparkand open http://localhost:8080 (SPARK_PORT changes the port). SPARK_ADMIN_PASSWORD='choose-a-password' spark

Read the script · Install in the README

Windows

01 · Install

Downloads the latest release, checks it and adds it to your PATH.

PowerShell
 irm https://raw.githubusercontent.com/curiosity-ai/spark/refs/heads/main/install.ps1 | iex

02 · Start it

Start it with a password for the console, and a folder for its models.

PowerShell
 $env:SPARK_ADMIN_PASSWORD = 'choose-a-password'; $env:SPARK_STORAGE = "$HOME\.curiosity\spark-data"; spark

What you see

Example session · what the installer prints
 irm https://raw.githubusercontent.com/curiosity-ai/spark/refs/heads/main/install.ps1 | iexInstalling Spark (win-x64)  downloading v26.10.6452: https://github.com/curiosity-ai/spark/releases/download/v26.10.6452/spark-26.10.6452-win-x64.zip  sha256 verified  installed C:\Users\you\.curiosity\spark Spark v26.10.6452 is installed.Start it with a management password (data and models go to .\storage unless SPARK_STORAGE says otherwise):  $env:SPARK_ADMIN_PASSWORD = 'choose-a-password'; $env:SPARK_STORAGE = 'C:\Users\you\.curiosity\spark-data'; sparkand open http://localhost:8080 (SPARK_PORT changes the port). $env:SPARK_ADMIN_PASSWORD = 'choose-a-password'; spark

Read the script · Install in the README

Docker

01 · Install

Models and settings live in the spark-data volume.

Terminal
 docker run -d --name spark -p 8080:8080 -v spark-data:/data \
   -e SPARK_ADMIN_PASSWORD='choose-a-password' curiosityai/spark:latest

02 · On a GPU host

With the NVIDIA container toolkit on the host, add --gpus all.

Terminal
 docker run -d --name spark --gpus all -p 8080:8080 -v spark-data:/data \
   -e SPARK_ADMIN_PASSWORD='choose-a-password' curiosityai/spark:latest

What you see

Example session · pulling and starting the image
 docker run -d --name spark -p 8080:8080 -v spark-data:/data -e SPARK_ADMIN_PASSWORD='choose-a-password' curiosityai/spark:latestOpen http://localhost:8080 and sign in as admin.

Docker in the README

To upgrade, run the install command again. Your models and settings are kept.

Your first request

From install to an answer

  1. 01

    Add a model

    Open localhost:8080, sign in as admin and search Hugging Face under Discover. A small one such as SmolLM2-135M-Instruct is enough to try it.

  2. 02

    Create a key

    Under API keys, create one. It is the bearer token your client sends.

  3. 03

    Call it

    Point an OpenAI SDK at http://localhost:8080/v1, or an Anthropic SDK at http://localhost:8080.

FAQ

Questions about Spark

Which models does Spark run?

Open models in the GGUF format, from Hugging Face or from a file you copy in: families such as Llama, Mistral, Qwen and Granite, vision models and embedding models. The console marks a model it cannot run before you download it.

Does Spark run on a GPU?

Spark places models on NVIDIA GPUs with CUDA 12 when it finds them, and runs them on the CPU otherwise, on x64 and ARM64.

Does one model serve several requests at once?

A model answers one request at a time, in the order they arrive. Different models answer side by side.

Does Spark keep my prompts?

The request log keeps prompts and answers for 30 days by default, so you can inspect them. Switch that off, or use a key with zero retention, and the content is never written to disk.

How does Studio use Spark?

Studio takes any OpenAI compatible endpoint as its model, and Spark is one. Create a key in Spark’s console and add the endpoint and key to Studio.

Can Spark serve an embedding model?

Yes. Embedding models answer the OpenAI embeddings endpoint, for semantic search.

How do I update it?

Run the install command again and restart Spark. Your models and settings are kept.

Your data. Your infrastructure.

Run the model on
your own machine