Docs
Sublet connects GPUs at home to people who need LLM inference. Hosts earn credits; buyers get an OpenAI-compatible API.
Host quick start
- Sign up.
- On the machine with the GPU (Node 20+), run login. It prints a code and a link: open it and approve the code on this site. You do this once per computer.
- Run start once. The agent finds your GPU and the GGUF files on your disk, benchmarks, and goes online in the live rack.
- On the market, take a request that fits your GPU, or one that is ready now because the model is already on your disk. Then run the start command it shows. Nobody else can take it, and you have 15 minutes to start before it goes back to the board.
- The agent loads the model and passes a first model check, then the booking timer starts. Booked hours pay into your wallet when the timer ends.
once per computer: approve the code on the website npx sublet-cli login --server https://sublet.duckdns.org npx sublet-cli start after you take a request on the market npx sublet-cli start r_7Kq2… npx sublet-cli jobs
No browser on the GPU machine? Create a host key in the host console and run npx sublet-cli login --key sh_… --server https://sublet.duckdns.org instead.
Test nodes (--simulation) cannot take paid work on the live server.
Reliability starts at 100%. Failed bookings, failed model checks, and lost connection lower it; see how Sublet checks hosts.
Buyer quick start
- Sign up: new accounts get free test credits.
- In the buyer console, create an API key (
sk-…, shown once). - Call an online host from the market per token, or post a booking: paste a HuggingFace
.gguflink, pick hours and a price. A host takes it, loads the model, passes a model check, and the timer starts.
curl https://sublet.duckdns.org/h/<username>/v1/chat/completions \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"Hello"}],"stream":true}'from openai import OpenAI
client = OpenAI(base_url="https://sublet.duckdns.org/r/<requestId>/v1", api_key="sk-your-api-key")
stream = client.chat.completions.create(
model="sublet",
messages=[{"role": "user", "content": "Hello"}],
stream=True,
)
for chunk in stream:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="")How Sublet checks hosts
Sublet does not take a host's word for which model it runs or how fast it is.
- Hidden model checks. The server sends check prompts that look like normal jobs, during bookings and to hosts that sell calls. It compares the token probabilities in each answer with other hosts that run the same model file (same SHA-256), or with a trusted reference host.
- Two failures end a booking. A failed check gets a second check right away. Two failures in a row end the booking: the buyer gets the money back for the time after the last good check, and the host gets a strike.
- Holds. Two strikes in 7 days put a host on hold, and so does a reliability score below 90%. Held hosts cannot take requests or sell calls until Sublet reviews them.
- Measured speed. The server measures each host's real tokens per second from the jobs it streams. The market shows that number and marks a host's own number as self-reported. A booking ends when the measured speed (the median of recent jobs) drops below the buyer's minimum, with a 20% margin for network jitter.
- Reliability score. Completed bookings × passed checks × time connected while booked. Each part starts as if the host had nine good results, so one bad result does not hold a new host.
Limits
- Hosts run the model on their own machine and can read prompts and answers. Do not send secrets.
- A model with few hosts stays “unverified” until a second host or a reference host answers the same check.
- Swapping in a different quantization of a big model is harder to detect than swapping in a different model.
- The thresholds come from real llama.cpp measurements and will be tuned.
API reference
Send Authorization: Bearer sk-… with every call. The body is the OpenAI chat format: messages, max_tokens (default 256, at most 4096), temperature, stream.
| method | path | what |
|---|---|---|
POST | /h/<username>/v1/chat/completions | Pay per token. Billed from your credits at the host price per 1M input and output tokens. |
POST | /r/<requestId>/v1/chat/completions | Your active booking. Unlimited calls, $0 each: the escrow already paid for the hours. |
GET | /h/<username>/v1/models | The model the host is serving. |
GET | /api/live | Server-sent events: one `snapshot` of the public network every second. |
Streaming
With "stream": true the response is OpenAI server-sent events. The final chunk has usage and sublet: { charged, costNanos }; booked calls report charged: false. Without streaming, the same two fields come in the JSON body.
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],
"usage":{"prompt_tokens":12,"completion_tokens":64,"total_tokens":76},
"sublet":{"charged":true,"costNanos":19200,"host":"ava","requestId":null}}
data: [DONE]Errors
Errors are JSON: { "error": "…" }.
401 | Missing or invalid API key. |
402 | Not enough credits for the call or the booking. |
404 | The booking does not exist or is not yours. |
409 | The host is serving a booking, or your booking is not active. |
503 | The host is offline, reconnecting, or held after failed checks. |
Money
Amounts are integer nanos: 1 USD = 1,000,000,000 nanos. The server counts streamed chunks itself and never bills from the host's token count. Test credits only, no real money yet.
Models
Only HuggingFace .gguf file links are accepted, as a single file (not split):
https://huggingface.co/<org>/<repo>/resolve/main/<file>.gguf
The server reads the size and SHA-256 from HuggingFace and estimates the VRAM the model needs. Hosts only load https://huggingface.co/ URLs.