# Quickstart

Install the CLI, get an answer, and know what to do when a step does not work. Budget ten
minutes.

**If you only want to see it work, you do not need this page yet.** Go to
[saylek.com](https://saylek.com), enter your email, and open the sign-in link that comes
back. You land in a Circle seeded with our demo machines, so you can ask a question and
read a real answer with nothing installed, no hardware of your own, and no invitation.
Come back here when you want a machine of yours answering too.

Saylek pools GPUs across a Circle of people you trust. When your GPU is idle it covers your
Circle; when yours is busy, or you do not have one, your Circle covers you. No money
changes hands, and every served request leaves a signed record of where it ran.

Before you start, know one thing about the model you are joining: a request your own
machine cannot serve runs on a Circle-mate's GPU, which means your prompt is handled by
their computer. That is the trade Saylek makes. [Privacy and
egress](/docs/privacy-and-egress) explains it and how to turn it off.

## Before you begin

| You need | Detail |
|---|---|
| A supported machine | Released binaries target **Linux x86_64** and **macOS arm64** (Apple Silicon). |
| An account | Create one at [saylek.com](https://saylek.com) with your email. It opens straight away. **No invitation is needed**, here or anywhere else: an invitation grows a Circle you are already in, it is not the door. |
| Your install command | Sign in, then press **Set it up** on your home page. It hands you the command in step 1 with a download token already in it, bound to your account. |
| Outbound HTTPS | The installer fetches a signed release; the daemon reaches your Circle over HTTPS. |
| A GPU | **Only if you want to host.** Consuming from your Circle works fine with no GPU at all. |

You do **not** need Docker, a Rust or Python toolchain, or `sudo`. Everything runs from the
released binary.

## 1. Install

Paste the command your home page handed you. It has this shape, with a real token where
`<token>` sits:

```bash
curl -fsSL https://saylek.com/i/<token> | sh
```

This verifies the release signature, installs `saylek` under `~/.saylek/`, registers a
user-level service, and launches `saylek gpu wizard`.

**Prefer to read before you run?** The URL serves a plain shell script, so fetch it, read
it, then run it:

```bash
curl -fsSL https://saylek.com/i/<token> -o saylek-install.sh
less saylek-install.sh
sh saylek-install.sh
```

**You know it worked when** `saylek --version` prints a version.

## 2. Check the daemon is up

```bash
saylek status
```

**You know it worked when** status reports the daemon running. Add `--watch` to live-tail
the state while something is settling.

If it is not running, start it with `saylek start`. Note that **`saylek start` runs in the
foreground and holds the terminal** until you stop it, which surprises people who expect it
to return to the prompt. Either open a second terminal for the commands below, or background
it with `saylek start &`. On a normal install a service manager keeps the daemon up for you,
so you should rarely need to run it by hand at all.

## 3. Ask your first question

```bash
saylek call "what is a trust-pool, in one sentence?"
```

**You know it worked when** you get an answer back.

If nothing is set up to answer yet, `saylek call` says so in plain language and points at
the next step, such as `saylek start` when the daemon is down or `saylek gpu wizard` when
no model is loaded. It does not dead-end. Run it with no prompt for a built-in one-line
smoke test.

## 4. Pick where you go next

You are running. Choose by what you came for:

- **Use your Circle's capacity from an app**: [Connect your app](/docs/connect-your-app)
  for a local client, or [Use your Circle from anywhere](/docs/connect-openai) for the
  hosted endpoint.
- **Contribute your GPU**: [Hosting your GPU](/docs/hosting).
- **Bring someone in**: [Invite flow](/docs/invite-flow).
- **Understand what you joined**: [Concepts](/docs/concepts).

## If something went wrong

Common first-run stops, with the full list on [Troubleshooting](/docs/troubleshooting):

| Symptom | Likely cause | Fix |
|---|---|---|
| `model_not_found` on your first call | Daemon is up but no model is loaded yet | `saylek gpu wizard`, then `saylek model ls` |
| `saylek: command not found` after install | `~/.saylek/bin` is not on your `PATH` | Open a new shell, or add it to your shell profile |
| Calls fail with no Host available | No Host in your Circle is online right now | `saylek status`; try again when one is back |
| Everything fails after enabling local-only | Local-only means local, including when local cannot answer. It stops Saylek routing to another member; it does not override a proxy upstream you configured yourself | Unset `local_only`, or load a model you can serve |

## Uninstalling

Two different scopes, and it matters which you mean:

```bash
saylek wipe                       # remove this device's local files only
saylek settings account delete    # leave Saylek entirely (90-day soft delete)
```

`saylek wipe` says nothing about the server: your account and Circles remain. To step away
without deleting anything, `saylek settings account deactivate` is fully reversible. The
[CLI reference](/docs/cli-reference) has the whole table.

## Next steps

- [Concepts](/docs/concepts): Circle, Host, Guest, Pool, and receipts.
- [Privacy and egress](/docs/privacy-and-egress): what leaves your machine.
- [Troubleshooting](/docs/troubleshooting): when a step does not behave.


---

# Concepts

Saylek is a **member-governed trust-pool for GPU inference**: a Circle you belong to,
rather than a vendor you pay. No money changes hands. Members contribute spare GPU
capacity to a shared Circle and draw on it when they need an answer.

Five ideas carry the whole product. Read this page before Quickstart if you want to know
what you are joining; read [Privacy and egress](/docs/privacy-and-egress) before you send
anything sensitive.

## Circle

A **Circle** is the trust boundary. It grows by invite, one person at a time, and there is
no anonymous pool: every machine that can serve you is run by a member of a Circle you
belong to.

Be precise about what that does and does not mean:

- On an **invite-only** Circle (the default when you create one), members are admitted by
  the Circle's owner, or by an owner or admin when an organization owns it. An ordinary
  member cannot bring someone in.
- That person is **not necessarily you**. Unless you own the Circle, someone else decides
  who joins it, and your requests can run on the machines they admit.
- A Circle can also be set to **open-join**, in which case people join without an invite at
  all.

So the unit of trust is the **Circle**, not each individual: joining one means accepting
whoever its owner admits. [Circles and membership](/docs/circles) covers both settings and
how to tell which kind you are in.

If you want a Circle where you personally approved every member, create it yourself and
keep it invite-only.

## Host and Guest

- A **Host** contributes GPU capacity. When a Host's GPU is idle, it serves requests from
  the Circle. Hosting is always an explicit choice: run `saylek host`. Nothing else turns
  it on.
- A **Guest** draws on that capacity. "Guest" is the internal name for the consuming side,
  not a stranger: a Guest is always a fellow member of your Circle.

Most members are both, at different times, on the same machine. Consuming never makes you
a Host, and hosting never happens by accident.

Your own work keeps priority on your own GPU. A Circle request is not allowed to starve
something you are waiting on yourself.

## Pool

The **Pool** is the aggregate capacity your Circle can draw on: the sum of every member's
idle GPU time. It is what covers a burst that would otherwise mean renting a GPU or
calling a hosted API.

## Consumption is on by default

This is the behaviour most worth understanding, because it is the one that acts without
being switched on.

When you ask for a model **your own machine cannot serve**, and a Host in your Circle can,
the request runs on that Host's GPU automatically. There is no toggle to find. Joining a
Circle is what enables it.

That means your prompt, and everything your tool put in the context window with it, leaves
your machine and is handled in the clear by another member's computer while it computes the
answer. Receipts prove **where** a request ran. They do not hide its content from the Host
that ran it.

Two facts bound this:

- With **no live Circle membership**, nothing egresses. Leaving your last Circle withdraws
  the default.
- **Local-only mode** stops Saylek routing your requests to anyone else, persistently or per
  request. It governs Saylek's own routing; it does not override a proxy upstream you
  configured yourself. See
  [Privacy and egress](/docs/privacy-and-egress).

## Receipts

Every served request leaves a signed record naming which machine ran it. Both sides keep a
copy. It is not there because anyone distrusts their Circle. It is what keeps the give and
take fair without anyone keeping score, and it is yours to replay and verify offline.

## No money

Saylek's release frame has no money movement, no billing, and no redeemable credits.
Contribution and consumption are social: reciprocity inside a Circle you chose, not a
transaction with a stranger.

## Next steps

- [Privacy and egress](/docs/privacy-and-egress): exactly what leaves your machine, and how to stop it.
- [Quickstart](/docs/quickstart): install and ask your first question.
- [Circles and membership](/docs/circles): joining, leaving, and who can reach you.


---

# Circles and membership

A Circle is the unit of trust, the unit of reach, and the thing you actually join. This
page covers who ends up in one, what that lets them do, and how to leave.

## What a Circle controls

Membership decides routing. A Host can only serve members of a Circle it belongs to, and
your requests can only reach Hosts in Circles you belong to. There is no path from a
stranger's machine to yours or back.

## How people get in

A Circle has two independent settings, and together they decide who can join.

| Setting | Values you can choose today | Default when you create one |
|---|---|---|
| Visibility | `unlisted`, `private` | `unlisted` |
| Admission policy | `invite-only`, `open-join` | `invite-only` |

Those defaults are deliberate: a Circle you create is neither publicly listed nor open to
join until you say so.

There is a third visibility, `public`, which puts a Circle in the browsable directory.
Creating one is not available yet while we validate that directory, so
`saylek circles create --visibility public` tells you it is coming soon rather than
making one. Public Circles that already exist stay browsable and joinable.

**Who can admit people:** minting invites is restricted to the Circle's owner (and, for a
Circle owned by an organization, its owner or admins). An ordinary member cannot bring
someone in. So on an invite-only Circle, everyone present was admitted by whoever runs it.

The consequence worth understanding:

- On an **invite-only** Circle, admission is controlled by the owner. If you trust the
  owner's judgement, you are trusting everyone in the Circle.
- On an **open-join** Circle, anyone who can reach it joins without an invite. If it is
  also `public` it appears in `saylek circles browse` and is joinable by anyone browsing.
  Since new Circles cannot be `public` yet, an open-join Circle you create today is
  reachable only by someone you hand its invite or circle id to.

"Everyone here was vouched for" is a property of an invite-only Circle, not of Circles in
general. Check which kind you are joining.

## Joining

For an invite-only Circle, redeem the invite you were given:

```bash
saylek circles join --invite https://saylek.com/c/<circle-id>/<token>
```

The bare composite form works too:

```bash
saylek circles join --invite <circle-id>:<token>
```

Both forms parse into identical requests before anything touches the network, so a
malformed invite fails locally rather than on the wire.

For an open-join Circle there is no token, so join by id:

```bash
saylek circles join --circle-id <circle-id>
```

**Joining is the consent.** Once you are in, requests your own machine cannot serve may run
on a Circle-mate's GPU by default. Read [Privacy and egress](/docs/privacy-and-egress)
before you join with a machine that handles sensitive work.

To find public Circles:

```bash
saylek circles browse
```

Only `public` Circles are listed. Unlisted and private ones are reached directly with a
join link.

## Creating and running one

```bash
saylek circles create --name "<name>" --slug <url-safe-slug>
```

`--slug` is optional at the command line but required by the server, so pass it or the
create fails. Add `--visibility` and `--admission-policy` only if you want something other
than the safe defaults above.

Then mint a link to bring people in:

```bash
saylek circles invites-mint --circle-id <circle-id>
```

Links are single-use and expire in 24 hours by default. `--uses N` (1 to 100) lets one link
admit up to N people, and `--expires` takes a duration such as `7d`, `24h`, or `1h`.

As written above it only prints the link, and delivering it is your choice. Add `--email`
and Saylek sends it for you:

```bash
saylek circles invites-mint --circle-id <circle-id> --email them@example.com
```

An emailed invite defaults to a 7-day expiry rather than 24 hours. See
[Invite flow](/docs/invite-flow) for the whole picture.

If a reusable link has spread further than you intended:

```bash
saylek circles invites-reset --circle-id <circle-id>
```

That revokes every active link you issued for the Circle, so previously shared links stop
admitting anyone. It is idempotent: resetting when nothing is active still succeeds. Mint a
fresh link afterwards.

## Seeing who is in

```bash
saylek circles members --circle-id <circle-id>
```

The roster shows each member's display name, role, join date, and user id. It shows a
placeholder where a display name is unset, because the roster is **email-blind by design**:
members do not see each other's email addresses.

Note the difference from:

```bash
saylek circles list
```

That one is **offline and device-local**. It reports the Circle credentials *this machine*
holds, not every Circle you belong to. It is honest about that limit in its own output.

## Removing someone

```bash
saylek circles kick --circle-id <circle-id> --user-id <user-id>
```

Find the user id with `saylek circles members`. Add `--yes` to skip the confirmation when
scripting. Kicking is reversible: they can rejoin with a fresh invite.

On an invite-only Circle, kick plus `invites-reset` is the complete removal, because only
an owner or admin can mint a way back in.

There is deliberately **no ban verb**. It would only add reach on an open-join Circle, where
a removed member could rejoin unaided, and the production posture is invite-only.

## Other owner commands

| Command | What it does |
|---|---|
| `saylek circles transfer` | Hand ownership of a Circle to another member. |
| `saylek circles archive` | Retire a Circle you own. |
| `saylek circles revoke` | Revoke this device's Circle credential, so it stops drawing on the pool. |

Run any of them with `--help` for the exact flags.

## Leaving

```bash
saylek circles leave <circle-id>
```

Note that `leave` takes the id **positionally**, unlike the owner commands above, which take
`--circle-id`. When in doubt, `saylek circles <command> --help` is authoritative.

Leaving is reversible: rejoin later with a new invite. It drops that Circle's models from
your reach within seconds, and your other Circles are unaffected.

Leaving your **last** Circle also withdraws the egress default: with no live membership,
Saylek stops routing your requests to anyone. Two caveats worth knowing, both covered on
[Privacy and egress](/docs/privacy-and-egress): your machine caches membership for a few
minutes, so the change is not instantaneous, and none of this touches a proxy upstream you
configured yourself.

For pausing or deleting your whole account instead, see
[Common commands](/docs/cli-reference).

## Next steps

- [Privacy and egress](/docs/privacy-and-egress): what a Circle-mate can see.
- [Invite flow](/docs/invite-flow): emailing an invite to one person.
- [Hosting your GPU](/docs/hosting): contributing capacity to a Circle.


---

# Invite flow

If you own a Circle, the command that invites someone into it is
`saylek circles invites-mint`. That is the one to reach for.

## Inviting someone into your Circle

```bash
saylek circles invites-mint --circle-id <circle-id> --email them@example.com
```

With `--email`, Saylek delivers the invite link to that address and prints it as well.
Leave `--email` off and it only prints the link, for when you would rather paste it into a
message yourself.

Two options worth knowing:

| Flag | What it does |
|---|---|
| `--uses N` | One reusable link that admits up to N members (1 to 100). Good for a group chat. Omit for a single-use link. |
| `--expires <duration>` | How long the link lives, such as `7d` or `24h`. Omit and an emailed invite defaults to 7 days, a printed one to 24 hours. |

You need the Circle id. `saylek circles list` shows the Circles you are in, with their ids.
(`saylek circles` on its own is a namespace rather than a command, so it prints help and
waits for a subcommand.)

To invalidate every outstanding link for a Circle at once, `saylek circles invites-reset
--circle-id <circle-id>`.

## Who can invite

Admission is controlled by the Circle's **owner**, or by an owner or admin when an
organization owns the Circle. An ordinary member cannot add someone to a Circle they do not
run. See [Circles and membership](/docs/circles) for admission settings and how to tell which
kind of Circle you are in.

## The other invite command, and why it is probably not yours

There is also a `saylek invite send` command. It brings someone onto **Saylek itself**
rather than into a Circle, and during closed beta it is
**restricted to the people running Saylek**: it authenticates with an admin token that
ordinary installs do not have, and without that token it fails with an error rather than
sending anything.

So if you want to bring a person in, use `circles invites-mint --email` above. `invite
send`, `invite list` and `invite revoke` are documented here only so that seeing them in
`--help` does not send you down a path that cannot work for you.

## Accepting an invite

The email carries a link built around the same token: `saylek.com/i/<token>` for the
one-line CLI install (see [Quickstart](/docs/quickstart)), or a web invite-acceptance
link. Either one walks the invited person through installing `saylek` and joining your
Circle.

## Leaving

Reversing an invite you sent, or leaving a Circle yourself, is covered on the
[CLI reference](/docs/cli-reference) page: pausing is reversible, leaving one Circle is
reversible (rejoin with a new invite), and leaving Saylek entirely is a soft delete.

## Next steps

- [Circles and membership](/docs/circles): invite links, admission policy, and removal.
- [Concepts](/docs/concepts): why the Circle is the trust boundary.
- [Quickstart](/docs/quickstart): what the invited person does next.


---

# Connect your app

Saylek speaks the OpenAI API, so anything that already talks to an OpenAI-compatible
endpoint (an SDK, LangChain, a coding assistant) can point at your daemon instead of a
hosted API, with no code change beyond the base URL.

> **Loopback does not mean local-only.** The endpoint below listens on `127.0.0.1`, but when
> your machine cannot serve a request the daemon sends it to a Host in your Circle by
> default, and your prompt is handled by that person's machine. Turn on local-only mode if
> you need requests to stay put, bearing in mind that it governs Saylek's routing and does
> not override a proxy upstream you configured yourself. See [Privacy and
> egress](/docs/privacy-and-egress).

## The endpoint

The daemon serves its OpenAI-compatible HTTP surface on loopback, by default at:

```
http://127.0.0.1:8443/v1
```

Override the address with the `SAYLEK_LISTEN` / `SAYLEK_PORT` env vars, or
`[daemon].listen` in `config.toml`. See `saylek --help`.

**Keep it on loopback.** The local API is **not authenticated**: it reads an
`Authorization` header and does not check it, because the only thing that can reach
`127.0.0.1` is you. Bind it to `0.0.0.0` or a LAN address and anyone who can route to that
port can use your machine's GPU, and can originate requests into your Circle under your
identity, with no credential at all. Saylek warns when you bind wide and drops your own
priority, but it does **not** add authentication. If you need it reachable from another
machine, put it behind something that authenticates, such as an SSH tunnel or a reverse
proxy you control, rather than opening the port.

## Point your client at it

Most OpenAI SDKs take a base URL and an API key. Locally, the daemon doesn't check the
key, so pass any non-empty string if your client insists on one:

```python
from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:8443/v1", api_key="local")

resp = client.chat.completions.create(
    model="qwen3-4b-instruct-2507-q4_k_m",
    messages=[{"role": "user", "content": "hello"}],
)
print(resp.choices[0].message.content)
```

## Before it can answer

A fresh install has the daemon running but nothing of its own to run yet.

What happens next depends on whether you are in a Circle. **If you are**, a model your
machine cannot serve is routed to a Circle-mate who can, so a call can succeed on a machine
with no model files at all. That is the default, and [Privacy and
egress](/docs/privacy-and-egress) is the page to read before you rely on it. **If you are
not in a Circle**, or no Host online can serve the model you asked for, the call returns
`model_not_found` until a `.gguf` lands under `~/.saylek/models/`.

To give your own machine something to serve: `saylek gpu wizard` (launched automatically
after install) walks you through picking a model; run `saylek model rescan` after dropping
in your own, and `saylek model ls` to confirm it was discovered.

## Confirm it's working

```bash
saylek call "hello"
```

If your app can reach `saylek call`'s built-in smoke test, it can reach the endpoint
above too.

## Next steps

- [Use your Circle from anywhere](/docs/connect-openai): the hosted endpoint, with a key.
- [Troubleshooting](/docs/troubleshooting): `model_not_found` and other first-call stops.
- [Concepts](/docs/concepts): how a request that runs on someone else's GPU stays honest.


---

# Use your Circle from anywhere

The hosted endpoint speaks the OpenAI API, so an existing OpenAI-compatible client can
reach your Circle from any machine with your API key. Nothing needs to run locally.

This is the **hosted** surface. For pointing a client at a daemon on your own machine, with
no key and no network hop, see [Connect your app](/docs/connect-your-app).

## Which one do I want

| | Local daemon | Hosted endpoint |
|---|---|---|
| Base URL | `http://127.0.0.1:8443/v1` | `https://api.saylek.com/v1` |
| Auth | None (any non-empty string) | Your member API key |
| Serves from | This machine first, then your Circle | Hosts across your Circles |
| Can requests leave your machine | Yes, unless local-only is set | Yes, always |
| Works when your machine is off | No | Yes |

Note the second row, because it surprises people: the local daemon is **not** a local-only
path. When your own machine cannot serve a request, the daemon falls back to a Host in your
Circle by default, exactly as the hosted endpoint does. Local-only mode is what makes the
daemon stay local. See [Privacy and egress](/docs/privacy-and-egress).

Use the hosted endpoint when you want your Circle's capacity from a machine that is not
running a daemon at all.

## 1. Create an API key

Create one from your account's keys page at `/account/keys`.

A key's secret is shown **once, at creation**. Save it then. If you lose it, create a new
key rather than trying to recover the old one.

## 2. Find a model your Circle serves

Model ids are carried verbatim, exactly as the Pool advertises them. There are no aliases,
so a name from another provider will not resolve. List what is actually available:

```bash
curl https://api.saylek.com/v1/models \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Pick an id from that response and use it as `MODEL_ID` below.

## 3. Point your client at it

Most OpenAI SDKs take a base URL and a key:

```python
from openai import OpenAI

client = OpenAI(
    base_url="https://api.saylek.com/v1",
    api_key="YOUR_API_KEY",
)

resp = client.chat.completions.create(
    model="MODEL_ID",
    messages=[{"role": "user", "content": "hello"}],
)
print(resp.choices[0].message.content)
```

```typescript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.saylek.com/v1",
  apiKey: "YOUR_API_KEY",
});

const resp = await client.chat.completions.create({
  model: "MODEL_ID",
  messages: [{ role: "user", content: "hello" }],
});
console.log(resp.choices[0].message.content);
```

Most tools that accept an OpenAI base URL take the same two values. Set
`OPENAI_BASE_URL` and `OPENAI_API_KEY` when a tool reads them from the environment:

```bash
export OPENAI_BASE_URL="https://api.saylek.com/v1"
export OPENAI_API_KEY="YOUR_API_KEY"
```

## 4. Confirm it works

```bash
curl https://api.saylek.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID",
    "messages": [{"role": "user", "content": "hello"}]
  }'
```

## When it can answer

Calls work while a Host in one of your Circles is online and serving the model you asked
for. When none is, requests fail until one comes back. That is the honest shape of a pool
of people's machines rather than a datacentre.

**Requests through this endpoint run on a Circle-mate's GPU**, which means your prompt is
handled by their machine. Read [Privacy and egress](/docs/privacy-and-egress) before
sending anything sensitive through it. The local-only controls described there apply to the
daemon, not to this hosted path: if you need a request to stay on your own machine, use the
local daemon.

**Provider-run tools have nothing behind them here.** A Host serves a model, not a search
engine or a sandbox, so a built-in web search returns an empty result set rather than an
error. Give your client a tool it runs itself instead:
[Web search](/docs/connect-anthropic#web-search).

## Next steps

- [Claude Code and the Anthropic SDK](/docs/connect-anthropic): the same Circle, Anthropic's dialect.
- [Connect your app](/docs/connect-your-app): the local, keyless daemon surface.
- [Troubleshooting](/docs/troubleshooting): 401s, 404s, and rejected model ids.


---

# Claude Code & the Anthropic SDK

Saylek speaks Anthropic's Messages API as well as the OpenAI one, so Claude Code and
the Anthropic SDKs can point at your Circle with no code change beyond a base URL and
a key. Calls ride the idle capacity of Hosts in your Circle. Your own work comes first.

This is the hosted member endpoint (your API key, dispatched to your Circle), not the
local daemon. For pointing a client at a daemon running on your own machine, see
[Connect your app](/docs/connect-your-app).

## The endpoint

Anthropic clients own the version segment: `ANTHROPIC_BASE_URL` is the origin, and the
client appends `/v1/messages` itself. So the base URL you set must **not** carry a
`/v1` suffix:

```
https://api.saylek.com
```

(The OpenAI-compatible surface, by contrast, uses `https://api.saylek.com/v1`: the extra
`/v1` is deliberate there and absent here.)

## Claude Code

```bash
export ANTHROPIC_BASE_URL="https://api.saylek.com"
export ANTHROPIC_AUTH_TOKEN="YOUR_API_KEY"
unset ANTHROPIC_API_KEY

# One id, every model slot Claude Code reaches for.
MODEL="MODEL_ID"
export ANTHROPIC_MODEL="$MODEL"
export ANTHROPIC_SMALL_FAST_MODEL="$MODEL"
export ANTHROPIC_DEFAULT_OPUS_MODEL="$MODEL"
export ANTHROPIC_DEFAULT_SONNET_MODEL="$MODEL"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$MODEL"
export CLAUDE_CODE_SUBAGENT_MODEL="$MODEL"

export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
export API_TIMEOUT_MS=600000              # self-hosted models answer slower than the stock timeout allows
export CLAUDE_CODE_MAX_CONTEXT_TOKENS=200000   # your model's real context window

claude
```

Find a live `MODEL_ID`:

```bash
curl https://api.saylek.com/v1/models -H "Authorization: Bearer YOUR_API_KEY"
```

Set every slot, not just `ANTHROPIC_MODEL`. Any slot left unset falls back to a
`claude-*` alias your Circle does not serve, and it fails partway into a run rather than
on the first call.

Claude Code does not recognize Pool model ids, so it assumes a 200,000-token context window
and compacts against that. If the model your Circle serves has a different window, set
`CLAUDE_CODE_MAX_CONTEXT_TOKENS` to the real number. Ask the Host, since the model list
does not report it. Do **not** append `[1m]` to the model name unless the model genuinely
has a 1M window: that lets a session grow past what the Host can accept, and the request is
refused outright rather than compacted.

Every line above needs `export`. A bare `NAME=value` sets a shell variable that `claude`
never sees.

Claude Code will also warn that your claude.ai connectors are disabled. That is expected:
an auth token pointed at Saylek takes precedence over a claude.ai login, so connectors
managed there do not load. Nothing else is affected, and your own MCP servers are
untouched. Turn the notice off in `.claude/settings.json`:

```json
{
  "disableClaudeAiConnectors": true
}
```

This stops Claude Code attempting a load that cannot succeed while you are authenticated
here. To get those connectors back, remove the setting **and** unset
`ANTHROPIC_AUTH_TOKEN`, which means using a claude.ai login for that session instead of
your Circle.

## Web search

Claude Code's built-in `WebSearch` and `WebFetch` are executed by the model provider, not
by whoever serves the request, and no search engine sits behind Saylek to honor them. So
Saylek **refuses the request with a 400** naming the tool, rather than serving it without
the search and letting the model answer as though it had one. Replace them in two steps.

1. Add a search server to `.mcp.json` at the root of your project:

```json
{
  "mcpServers": {
    "search": {
      "command": "npx",
      "args": ["-y", "mcp-searxng"],
      "env": { "SEARXNG_URL": "http://YOUR_SEARXNG_HOST:8080" }
    }
  }
}
```

2. In `.claude/settings.json`, deny the built-ins and grant the MCP tools:

```json
{
  "permissions": {
    "deny": ["WebSearch", "WebFetch"],
    "allow": ["mcp__search__searxng_web_search", "mcp__search__web_url_read"]
  }
}
```

Then run `claude` once in that directory and accept the workspace-trust prompt. Until you
do, Claude Code honors the `deny` but ignores the `allow`, which is the worst of both: the
built-ins are off and your search tool is ungranted, so the model calls it every turn and is
refused every turn. A scripted `claude -p` in a fresh checkout hits this, because there is
no prompt to accept.

Both steps are needed. Leave the built-ins enabled and the model picks them every time and
never calls your MCP tool.

Both must also land in the config **that session actually loads**, which is the trap that
looks exactly like the recipe not working. Claude Code reads settings and MCP registrations
once, at startup, from the home directory the session was launched with. A session already
running will not see either change, and a session launched with a different `HOME` reads
a different config entirely and behaves as if you configured nothing. Restart, then
confirm with `/mcp` that `search` reads **connected**; if it does not, you edited a file
that session is not reading.

The `allow` half matters as much as the `deny`. Without it the model calls your search
tool and the request is refused for want of permission. Interactively you get a prompt;
a scripted `claude -p` run just fails. The names are the server's own tools prefixed
with `mcp__<server>__`, so they follow whichever server you picked: `mcp-searxng` exposes
`searxng_web_search` and `web_url_read`, not `web_search`. Check yours with `/mcp` in a
session, or `claude mcp list`.

Confirm the server is live before blaming the search:

```bash
claude mcp list
```

`✔ Connected` means the MCP server started, not that the search backend answered. For that,
query the backend directly. A 403 rather than a 200 is why results come back empty.

Any MCP search server works. SearXNG can be self-hosted, which keeps your queries off a
third-party search API; if you run one, its JSON API and bot limiter both need attention,
since the defaults refuse programmatic callers.

## The Anthropic SDK

The Python and TypeScript SDKs take a base URL and an auth token directly:

```python
from anthropic import Anthropic

client = Anthropic(base_url="https://api.saylek.com", auth_token="YOUR_API_KEY")
resp = client.messages.create(
    model="MODEL_ID",
    max_tokens=1024,
    messages=[{"role": "user", "content": "How are you doing?"}],
)
print(resp.content[0].text)
```

```typescript
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  baseURL: "https://api.saylek.com",
  authToken: "YOUR_API_KEY",
});
const resp = await client.messages.create({
  model: "MODEL_ID",
  max_tokens: 1024,
  messages: [{ role: "user", content: "How are you doing?" }],
});
const [block] = resp.content;
if (block.type === "text") console.log(block.text);
```

## curl

The raw Messages API endpoint accepts either `x-api-key` or `Authorization: Bearer`, plus the
required `anthropic-version` header:

```bash
curl https://api.saylek.com/v1/messages \
  -H "x-api-key: YOUR_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "How are you doing?"}]
  }'
```

## When it can answer

Calls work while a Host in your Circle is online; when none is, requests fail until one
comes back.

A key's secret is shown once, at creation, so paste it in place of `YOUR_API_KEY` above and
keep your copy safe. To be exact about where it travels: your key **is** sent to Saylek on
every call, because that is what authenticates you. It is **not** passed on to the Host that
serves the request. If you lose a key or a key leaks, revoke it at `/account/keys` and
create another.

## Next steps

- [Use your Circle from anywhere](/docs/connect-openai): the same endpoint, OpenAI dialect.
- [Privacy and egress](/docs/privacy-and-egress): what a Host sees when it serves your agent.
- [Troubleshooting](/docs/troubleshooting): 401s, 404s, and rejected model ids.


---

# Hosting your GPU

Hosting is how capacity gets into the pool. It is always an explicit choice: nothing you do
as a consumer ever turns your machine into a Host.

## What hosting commits you to

When you host, your machine serves requests from members of your Circles while your GPU is
idle. In exchange your own requests can draw on everyone else's idle capacity.

Two things are worth being clear about before you start:

- **Your own work keeps priority on your own GPU.** A Circle request is not allowed to
  starve something you are waiting on yourself.
- **You will see what you serve.** Serving a request means your machine handles that
  member's prompt in the clear, because that is how it computes the answer. The other side
  of this is documented for consumers in [Privacy and
  egress](/docs/privacy-and-egress); as a Host you are the party on the receiving end of
  that trust.

The full version of what arming hosting commits you to, including what serving does *not*
expose and who is answerable for what, is the [Acceptable Use Policy](/aup). Read it before
you run the wizard below rather than after: running it is the act that agrees to it.

## Requirements

| | |
|---|---|
| Hardware | A GPU the daemon can serve from. NVIDIA via `cuda`, Apple Silicon via `metal`. |
| Binary | A build with an inference backend compiled in. Released binaries have one. |
| Membership | You must be an active member of the Circle you host for. |

A from-source build with no `--features` flag compiles but cannot serve: the first call
returns HTTP 503 `no inference backend compiled in`. Build with `cpu`, `cuda`, or `metal`.

## Start hosting

Get a model serving first, if you have not already:

```bash
saylek gpu wizard
```

Then arm hosting:

```bash
saylek host wizard
```

The wizard is what actually turns hosting on: it sets `[host].enabled`, resolves and writes
the models you will advertise, mints the host credential and installs the background service.
`saylek gpu wizard` above gets a model serving locally, which is a different thing and does
not arm contribution. Bare `saylek host` is the serve verb for a machine that is already set
up; on one that is not, it refuses and points you back here.

Afterwards, `saylek host` runs the up-path in the foreground if you want to watch it.

Confirm what your machine is offering:

```bash
saylek models     # what this machine can serve right now
saylek status     # health, and whether you are connected
```

## Stopping: three different scopes

These are easy to confuse, and one of them is much larger than people expect.

| You want to | Command | What keeps working |
|---|---|---|
| Stop **contributing**, keep using Saylek yourself | `saylek host pause` | Your own inference, your Circles, your standing |
| Stop the **daemon** entirely | `saylek stop` | Nothing. `saylek call` will not answer until `saylek start` |
| Step away from Saylek but keep your account | `saylek settings account deactivate` | Reversible with `activate` |

`saylek host pause` is the small, targeted one, and it is what the "Pause contributing"
control on your home page does.

There is no bare `saylek pause`. "Pause" means two different things at two different scopes,
so the CLI does not guess which one you meant: it answers with both commands and lets you
pick. Use `saylek host pause` when you mean contributing, and `saylek stop` when you mean
the daemon.

## Checking your contribution

```bash
saylek statement <YYYY-MM>
```

An honest, no-money record of where each request ran. It is a record of work served, not a
bill: nothing is owed in either direction.

## Next steps

- [Circles and membership](/docs/circles): who your Host will serve.
- [Troubleshooting](/docs/troubleshooting): when your machine shows as offline.
- [CLI reference](/docs/cli-reference): the full everyday command table.


---

# Troubleshooting

Symptoms first. Each entry says what the state actually is, not just what to type.

Start by getting the daemon's own view:

```bash
saylek status
```

Add `--watch` to live-tail it while something is settling.

## Install and startup

### `saylek: command not found`

The binary installed to `~/.saylek/bin` but that directory is not on your `PATH`. Open a
new shell first, since the installer edits your shell profile and the current session will
not have picked it up. If it still fails, add `~/.saylek/bin` to `PATH` yourself.

### The daemon is not running

```bash
saylek start
```

The installer registers a user-level service, so this is normally only needed after a
manual stop.

## First call

### `model_not_found`

The daemon is up but has no model loaded. A fresh install is expected to be in this state.

```bash
saylek gpu wizard     # guided: pick and fetch a model
saylek model ls       # confirm it was discovered
```

If you dropped a `.gguf` into `~/.saylek/models/` yourself, tell the daemon to look again:

```bash
saylek model rescan
```

### HTTP 503, `no inference backend compiled in`

You are running a binary built with no inference backend. This only happens on a
from-source build: `cargo build --release` without a `--features` flag compiles, but the
result cannot serve.

Rebuild with a backend that matches your hardware: `cpu` (portable), `cuda` (NVIDIA), or
`metal` (Apple Silicon). Released binaries already carry one.

### Requests fail and no Host is available

Your Circle can only answer while a Host in it is online. If none is, calls for models you
cannot serve locally will fail until one comes back. Check with `saylek status`.

### Every request fails after you enabled local-only

This is local-only working as designed, not a bug. Local-only stops Saylek routing your
request to another member: it serves locally or it fails. If your machine cannot serve the
model you asked for, every such request now fails.

(One scope note, since it surprises people in the other direction: local-only governs
Saylek's own routing. It does not override a proxy upstream you configured yourself, which
still receives requests that resolve to it.)

Either load a model you can serve locally, or turn local-only back off in
`~/.saylek/config.toml`:

```toml
[federation]
local_only = false
```

See [Privacy and egress](/docs/privacy-and-egress).

### Nothing egresses even though local-only is off

Check that you still belong to a Circle. With **zero live memberships** the system fails
closed and keeps everything local, by design: leaving your last Circle withdraws the egress
default.

```bash
saylek circles list
```

Remember that this is the offline, device-local view. It reports what this machine holds
credentials for, not every Circle you belong to.

## Connecting an app

### 401 or 403 from the hosted endpoint

Your API key is wrong, revoked, or not being sent. A key's secret is shown **once**, at
creation, so if you did not save it, create a new one rather than hunting for it.

### Claude Code ignores your key

`ANTHROPIC_API_KEY` overrides `ANTHROPIC_AUTH_TOKEN`. Unset it:

```bash
unset ANTHROPIC_API_KEY
```

### 404 on the hosted endpoint

Almost always the `/v1` suffix, which differs by dialect and is easy to cross over:

| Client | Base URL |
|---|---|
| OpenAI-compatible | `https://api.saylek.com/v1` |
| Anthropic clients | `https://api.saylek.com` (the client appends `/v1/messages` itself) |

### The model id is rejected

Saylek carries the Pool-advertised model id verbatim. There are no `claude-*` or `gpt-*`
aliases. List what your Circle is actually serving and use one of those ids:

```bash
curl https://api.saylek.com/v1/models -H "Authorization: Bearer YOUR_API_KEY"
```

### Web search finds nothing, and nothing errors

A tool your client runs on its own machine is fine. A tool the model *provider* runs is
not: a Host serves a model, not a search engine. Claude Code's `WebSearch` and
`WebFetch` are provider-run, so they hand back an empty result set with no error, and the
answer arrives with no sources and no warning.

Replace them with a search tool your client runs itself:
[Web search](/docs/connect-anthropic#web-search).

## Hosting

### You are hosting but your machine shows as offline

Check that the daemon is running and reachable, and that `saylek status` reports it
connected. Hosting is a separate explicit step from consuming: if you never ran
`saylek host`, your machine is not offering capacity and is not supposed to appear as a
Host.

### Your own work feels slow while serving

Your own work keeps priority on your own GPU. If that is not what you are seeing, capture
`saylek status --watch` output and tell us, because that is a defect rather than a setting.

## Still stuck

Reach us from [/support](/support). Include what you ran, what you expected, and what
happened, plus the output of `saylek status`.

## Next steps

- [Quickstart](/docs/quickstart): the first-run path.
- [Privacy and egress](/docs/privacy-and-egress): local-only, in full.
- [CLI reference](/docs/cli-reference): the command tables.


---

# Privacy and egress

The one sentence: **when a request runs on a Circle-mate's GPU, that person's machine sees
your prompt.** Everything below is the detail behind that sentence, including how to turn
it off.

This page describes the running system during closed beta. The formal policy is at
[/privacy](/privacy); this is the operator's-eye version.

## What leaves your machine, and when

Saylek serves a request locally when it can. When your own machine **cannot** serve the
model you asked for, and a Host in one of your Circles can, the request goes to that Host
automatically. You do not switch this on. Joining a Circle is what enables it.

What travels:

- Your **prompt**, and everything your tool put in the context window with it. For a coding
  agent that routinely means file contents, diffs, stack traces, and anything else it read
  on the way to the task.
- The **completion** comes back the same way.

The Host's machine handles both in the clear. It has to: that is how it computes the
answer. The Host is a peer running `saylek host`, not an opaque cloud endpoint, but it is
still a different person's computer.

### It does not go straight there

Your request reaches that Host **by way of our registry**, which routes it. So your prompt
is on Saylek's server too, not only on the Host's machine. We do not read it and we do not
train on it, but it would be wrong to let you picture a direct machine-to-machine hop.

How long it can sit there is the least tidy fact on this page: the routing queue is trimmed
**by count** (about 10,000 entries) and **never by age**. A busy queue displaces your prompt
in moments. A quiet one can hold it indefinitely, because nothing deletes it for being old.
The [privacy notice](/privacy) states this in the same terms.

### What the Host learns about you

A **key fingerprint**, not your name or email. It is **stable across requests**, so a Host
can tell that many requests came from the same member. They cannot tell *which* member from
that alone: pseudonymous, not anonymous. The registry, which does the routing, does know
which member you are.

### What is kept afterwards

Nothing on a machine is deleted automatically. Receipts and activity logs stay until someone
removes them by hand (`saylek wipe`), on your machine and on the Host's alike. Receipts hold
**hashes, not text**, so they are not a transcript of what you typed. The full inventory is
in the [privacy notice](/privacy).

## The boundary is social, not cryptographic

Saylek's answer to "who can see my requests" is **membership**, not encryption:

- Consumption routes to Hosts **in your Circles only**. A stranger's Host is never a
  serving candidate for you, and you are never one for them.
- There is no setting that makes a Circle-mate unable to see what they serve. That is not
  a missing feature, it is the model.

The honest rule of thumb: **do not send a Circle anything you would not hand to its
members directly.** It is the same judgement you already make about who you let watch your
screen.

Be precise about who a Circle-mate can be. On an **invite-only** Circle (the default),
members are admitted by the Circle's owner, or by an owner or admin when an organization
owns it, so unless you own the Circle someone else chose them. A Circle can also be set to
**open-join**, in which case people join without an invite and may be strangers to you.
See [Circles and membership](/docs/circles) for how to tell which kind you are in.

## Turning egress off

Two controls, and both can only force a request to stay local. Neither can ever force a
request out.

### Persistent: local-only mode

Set in `~/.saylek/config.toml`:

```toml
[federation]
local_only = true
```

With this on, **Saylek will not route your request to a Circle-mate.** It serves locally or
it fails.

Be precise about the scope, in two directions.

It stops your prompts, uploads, and completions going to another member. Saylek still talks
to our servers for the ordinary running of your account, such as signing in, checking Circle
memberships, and looking for updates. Local-only is a content control, not an airgap.

It also does **not** override an upstream **you** configured yourself. If you have registered
a proxy upstream in `upstreams.toml` and you call a model that resolves to it, the request
is forwarded there, local-only or not. That is deliberate in the sense that you set it up,
but it is not what "local-only" sounds like, so: local-only governs *Saylek's* routing, not
a destination you added by hand. If you want nothing forwarded anywhere, turn the upstream
off as well.

Be clear about the trade: **if your machine has no GPU capable of serving the model, every
such request now fails.** That is the honest semantics, not a bug. Local-only means local,
including when local cannot answer.

### Per request: a header

For a single call, without changing your config:

```bash
curl http://127.0.0.1:8443/v1/chat/completions \
  -H "x-saylek-local-only: 1" \
  -H "Content-Type: application/json" \
  -d '{"model": "MODEL_ID", "messages": [{"role": "user", "content": "hello"}]}'
```

The header forces that one request local. It cannot override persistent local-only mode to
force egress.

### Leaving withdraws it

Hold **no live Circle membership** and the system fails closed to local. Leaving your last
Circle withdraws the standing default.

One honest caveat about timing: your machine caches what it knows about your memberships for
a short period, on the order of minutes, rather than re-checking on every single request. So
immediately after you leave, a request can still be sent before your machine has caught up.
If you want the change to take effect the instant you make it rather than shortly afterwards,
set local-only as well, which takes effect at once because it is read on your side.

## What receipts prove

Every served call mints a signed receipt. A Host-served receipt names the serving node and
key fingerprint, co-signed by both sides. Verifying is offline, and the command depends on
whether you want one receipt or all of them:

```bash
saylek receipt show <id> --verify   # one receipt, with the signature check appended
saylek receipt verify --all         # walk every receipt under ~/.saylek/receipts/
```

`saylek receipt verify` on its own does nothing on purpose: batch verification is the kind
of thing you should have to ask for explicitly, so it refuses without `--all`.

| Receipts prove | Receipts do not prove |
|---|---|
| This request ran on this Host, on this model, at this time | That the content stayed private from that Host |
| Both parties attest to it | Anything about confidentiality |

A verified receipt means "this is who ran it". It does not mean "this was private". The
Host signing your receipt is the same Host that saw your prompt. `saylek receipt show <id>`
says exactly this in plain language before it prints the audit body.

## What we do not claim

- **Not encrypted from the Host.** Federated consumption is readable by the serving Host.
  It is TLS-encrypted *in transit*, which protects it from anyone in between, not from the
  people it is travelling to.
- **Not confidential compute.** Making a Host *unable* to read what it serves (enclaves,
  content-blinding) is a V-Next direction under assessment. It is not in the closed beta,
  and nothing here depends on it.
- **Not "your prompt is never written to disk anywhere."** Saylek has an opt-in debugging
  setting (`[debug] traces = true`) that writes prompts and replies to a plaintext file so
  an operator can see what their own machine is doing. It is **off by default**, and as the
  code stands a Circle-mate's request does not reach that writer. But that is because of how
  the request happens to be shaped, not because a rule stops it. We are turning that into an
  actual rule. Until then we would rather state the shape of it than round it up to a
  guarantee.

If you point Saylek at a different registry with an `http://` address it will use an
**unencrypted** connection and will not warn you. Do not do that outside a trusted local
network.

## Next steps

- [Circles and membership](/docs/circles): who ends up in your Circle, and how to leave.
- [Concepts](/docs/concepts): where this sits in the whole model.
- [/privacy](/privacy): the formal policy page.


---

# API reference

What Saylek's API surface actually accepts, and what it does not. For getting started, use
[Connect your app](/docs/connect-your-app) (local) or [Use your Circle from
anywhere](/docs/connect-openai) (hosted).

## Base URLs

| Surface | Base URL | Auth |
|---|---|---|
| Local daemon | `http://127.0.0.1:8443/v1` | None. Pass any non-empty string if your client insists. |
| Hosted, OpenAI dialect | `https://api.saylek.com/v1` | `Authorization: Bearer <key>` |
| Hosted, Anthropic dialect | `https://api.saylek.com` | `x-api-key` or `Authorization: Bearer`, plus `anthropic-version` |

The Anthropic base URL carries **no** `/v1`, because Anthropic clients append
`/v1/messages` themselves. The OpenAI base URL **does**. Getting this backwards is the most
common cause of a 404.

## Endpoints

The daemon serves the following OpenAI-dialect routes:

| Endpoint | Purpose |
|---|---|
| `GET /v1/models` | What **this daemon** can serve: models discovered on this machine, plus any upstreams you configured. It is **not** the list of what your Circle can reach. For that, run `saylek models --circle`. |
| `POST /v1/chat/completions` | Chat completions. The main path, and the one to build on. |
| `POST /v1/embeddings` | Embeddings. |
| `POST /v1/audio/transcriptions` | Audio transcription. |
| `POST /v1/responses` | Responses-style calls, but **only against a proxy upstream you have configured**. A local model or a Circle Host returns `model_not_found` here. Use the chat path instead. |
| `POST /v1/completions` | **Not implemented.** The route exists and answers 501. It is listed so you do not spend an afternoon wondering why the legacy path 404s differently than you expected. Use the chat path. |

The hosted Anthropic surface adds `POST /v1/messages`, covered on [Claude Code and the
Anthropic SDK](/docs/connect-anthropic).

## Streaming

`stream: true` is supported on the chat path and emits standard OpenAI SSE frames, so a
client that already consumes OpenAI streaming works without changes.

## Model ids are verbatim

Saylek carries the model id your Pool advertises, exactly as advertised. There is **no**
aliasing layer: `gpt-4o`, `claude-3-5-sonnet` and similar names from other providers do not
resolve, even through the Anthropic dialect. Always discover first:

```bash
curl https://api.saylek.com/v1/models -H "Authorization: Bearer YOUR_API_KEY"
```

## Rate limiting and availability

**There is a rate limiter, and it is on by default.** Your local daemon ships with a limit of
**100 requests per second** with a **burst allowance of 200**, and it answers **HTTP 429**
when you exceed it. It is a spike absorber rather than a quota: you are unlikely to meet it
by hand, and quite likely to meet it with a parallel batch job. Handle 429 and back off. The
values live under `[ratelimit]` in `~/.saylek/config.toml` if you need to change them on
your own machine.

What does **not** exist yet is a published **quota or token ceiling** on the hosted surface.
Rather than print a number we have not committed to, we are leaving that unstated until it
is real.

Availability is the failure mode that will actually bite you, because capacity comes from
members' machines:

- A request for a model **no online Host serves** fails, rather than queueing indefinitely.
- Locally, a request for a model with **nothing loaded** returns `model_not_found`.
- A daemon built with no inference backend returns HTTP 503 `no inference backend compiled
  in`.

See [Troubleshooting](/docs/troubleshooting) for the error shapes.

## Limits and status codes a client has to handle

| | |
|---|---|
| **Request body** | **32 MiB** on the chat, embeddings and responses paths. Larger bodies are rejected at the edge with **413**. Audio transcription is bounded separately by the upload itself. |
| **Rate** | 100 requests/second, burst 200. Over that is **429**. |
| **Retry-After** | Sent on **429** and on the **503** you get when the pool is full. Honour it rather than retrying immediately; it is a short hint, because a slot usually frees quickly. |

The status codes worth branching on:

| Code | What it means | What to do |
|---|---|---|
| `400` | The request is malformed. | Fix the request. Retrying will not help. |
| `401` | Key missing, wrong, or revoked. On the **hosted** surface only; a local daemon does not check keys. | Check the key. |
| `404` | Usually the base URL, not the model. See the note at the top of this page. | Check whether your base URL should include `/v1`. |
| `413` | Body over 32 MiB. | Send less. |
| `429` | Rate limited. | Back off, honour `Retry-After`. |
| `501` | The route exists but is not implemented, for example `/v1/completions`. | Use the chat path. |
| `503` | No capacity: pool full, or no inference backend compiled in. | Retry with `Retry-After`, or check that a Host is online. |

A model your Circle cannot serve comes back as `model_not_found` rather than as a
transport error, so branch on the error body and not only on the status.

## Keys

Member API keys are created at `/account/keys`. A key's secret is shown once, at creation.
Keys are member-scoped, so a key reaches every Circle you belong to in its region.

Revoke a device's Circle credential with `saylek circles revoke`; that stops it drawing on
the pool.

## Where requests run

Every hosted call, and every local call your own machine cannot serve, runs on a
Circle-mate's GPU. Build with that in mind. [Privacy and
egress](/docs/privacy-and-egress) is the page to read before sending anything sensitive
through an integration.

## Next steps

- [Use your Circle from anywhere](/docs/connect-openai): hosted setup, end to end.
- [Troubleshooting](/docs/troubleshooting): 401s, 404s, and rejected model ids.
- [Privacy and egress](/docs/privacy-and-egress): what leaves the machine.


---

# Common commands

> **Generated from [`README.md`](https://github.com/Saylek-ai/TokEx/blob/main/README.md)
> by `scripts/generate-docs-cli-reference.mjs`. The `docs-parity` CI check fails closed
> if this page and the README's tables ever drift apart. Don't hand-edit the tables below;
> edit README.md and re-run the generator.**

This is the everyday subset, not the whole command tree. It is deliberately short: these
are the commands a member actually reaches for.

**The CLI is the complete reference for itself.** `saylek --help` lists every command,
`saylek <command> --help` gives full detail for one, `saylek help <topic>` covers curated
learning topics, and bare `saylek` shows the grouped everyday-first overview.

Task-shaped pages cover the commands not listed here:
[Circles and membership](/docs/circles) for `saylek circles`,
[Hosting your GPU](/docs/hosting) for `saylek host`,
[Invite flow](/docs/invite-flow) for bringing someone into a Circle you own
(`saylek circles invite`, also spelled `saylek circles invites-mint`), and
[Troubleshooting](/docs/troubleshooting) for `saylek model` and the daemon verbs.

Top-level `saylek invite` is a different command with the same word in it: it invites
someone to install Saylek itself, and it is restricted to the people running Saylek. To
bring a person into your Circle, the command is `saylek circles invite`.

## Everyday commands

| Command | What it does |
|---|---|
| `saylek status` | Is your node healthy? (`--watch` to live-tail) |
| `saylek models` | What this machine can serve right now |
| `saylek host` | Contribute your GPU to your Circle. Your own work keeps priority |
| `saylek statement <YYYY-MM>` | An honest, no-money record of where each request ran |
| `saylek --help` | Everything else |

## Leaving

Leaving is meant to be honest and reachable, at whatever scope you mean, and the first
step is reversible.

| You want to… | Command | Reversible? |
|---|---|---|
| **Pause**: stop serving/consuming but keep your Circles + standing | `saylek settings account deactivate` | Yes. `saylek settings account activate` turns it back on. |
| Leave **one Circle** | `saylek circles leave <circle>` | Yes. Rejoin later with a new invite. |
| Leave **Saylek entirely**: delete your account + wipe this device | `saylek settings account delete` | Account: 90-day soft-delete. This device's keys: **irreversible**. |
| Remove **one machine** from your Circle, keeping your account | `saylek host forget` | No. Set it up again with `saylek host wizard`. |
| Remove only this device's local files | `saylek wipe` | Local only: the machine stays registered unless you also `saylek host forget` (or answer the prompt). |

`saylek leave` isn't a command on its own. It points you at both `circles leave` and
`settings account delete` so you can pick the scope you mean.

## Next steps

- [Quickstart](/docs/quickstart): install and ask your first question.
- [Circles and membership](/docs/circles): join, create, leave, and remove.
- [Hosting your GPU](/docs/hosting): contribute capacity, and the three ways to stop.


---

# Evaluate Saylek (summary)

> SUMMARY ONLY. The canonical page is https://saylek.com/evaluate (HTML, last
> reviewed 2026-08-03). Where this summary and that page differ, the page governs.

- Public and unauthenticated: the whole page is readable with no account, which is the point of it. A technical evaluator previously had to create an account before they could establish anything about the system.
- The request path crosses three boundaries: your machine, Saylek's registry (which routes the prompt and therefore handles it), and the serving member's machine (which reads it in the clear). There is no end-to-end encryption and no enclave.
- The local daemon API on 127.0.0.1:8443 is NOT authenticated: it reads an Authorization header and does not check it, so anything that can reach the port can use it.
- Not joining a Circle, and local-only mode, are the controls that prevent Circle routing. Local-only fails a request rather than sending it, and neither control overrides a proxy upstream the member configured themselves.
- Released binaries target Linux x86_64 (glibc 2.31 floor) and macOS arm64 only. There is no Windows build. Backends are cpu, cuda and metal; a build with no backend compiled in returns 503 on the first call.
- API surfaces: the local daemon at http://127.0.0.1:8443/v1 with no auth, the hosted OpenAI dialect at https://api.saylek.com/v1 with a bearer key, and the hosted Anthropic dialect at https://api.saylek.com with no /v1 suffix. `/v1/completions` answers 501, and `/v1/responses` works only against a configured proxy upstream.
- Provenance can be checked offline: `saylek-verify` is built from the receipt core alone and a repository test fails the build if it ever links daemon code, so the verifier cannot be the thing that produced the receipt.
- BUT there is no anonymous way to run that check today: the verifier download is behind the same token-gated path as the daemon binaries and returns 404 to an anonymous request, and no sample receipt is published. The page says so rather than describing a proof a reader cannot run.
- Also named as missing rather than omitted: there is no recording of a real session, so the page is documentation rather than demonstration.
- Accounts are open: registration needs an email address and a bot check, with no invitation and no allowlist. The binaries are the gated part, behind a download token minted for a signed-in member.
- Stated limitations: beta, no availability guarantee (the serving machine can be switched off mid-request), inference only, owner priority on a Host's machine is bounded rather than instant, and there is no separate terms-acceptance step yet.

---

# Terms of Service (summary)

> SUMMARY ONLY. The canonical page is https://saylek.com/terms (HTML, last
> reviewed 2026-07-24). Where this summary and that page differ, the page governs.

- Joining a Circle is your consent to Circle routing: a request your device cannot serve runs on a Circle-mate's GPU, and your prompt leaves your device as text, not as a hash or a summary.
- The prompt is NOT encrypted from the Host: their machine reads it in order to run it. There is no end-to-end encryption and no secure enclave.
- The request reaches the Host by way of Saylek's registry, so Saylek handles the prompt too.
- Local-only mode (`local_only = true` under `[federation]`), and holding no Circle membership, prevent the routing. Local-only fails a request rather than sending it. It governs Saylek's own routing and does NOT override a proxy upstream the member configured themselves.
- Hosts must not collect, publish, or go looking through the request content they receive in order to serve it.
- No money moves: no fees, no payouts, no redeemable credits. Contribution is a social record, not a currency, with no cash value.
- Beta: no uptime or availability guarantee, no warranty. The machine serving you can be switched off mid-request.
- Saylek cannot undo what has left your machine: once a request has gone to a Host it is on their machine.
- Saylek is operated by Saylek LLC, a Washington limited liability company; these terms are governed by Washington State law, with venue in the courts sitting in Washington.
- Still outstanding and deliberately not invented: a minimum age and the GDPR controller characterisation. There is also no acceptance step recording assent yet.

---

# Acceptable Use Policy (summary)

> SUMMARY ONLY. The canonical page is https://saylek.com/aup (HTML, last
> reviewed 2026-08-03). Where this summary and that page differ, the page governs.

- Nothing inspects, classifies, or filters request content. There is no moderation layer between the sender and the machine that serves them. A model backend may refuse on its own policy and that refusal is passed back, but that is the model's judgement, not Saylek's.
- Prohibited to send: other people's private data, anything illegal in either party's jurisdiction, sexual content involving children, work aimed at harming people, and live credentials or keys.
- Prohibited against the pool: sustained bulk-compute load, attacking or probing other members' machines, deanonymising or profiling members from what passes through a Host, and advertising models or capacity a machine does not have.
- Hosting is armed only by `saylek host wizard`; consuming and joining a Circle never arm it. Running that command is how a Host consents to what follows.
- A Host runs other members' work without being asked each time: there is NO approve-each-request step, and a Host does not see a request before it runs.
- A Host reads the prompts it serves in the clear. What it does not get: the sender's name or email (a key fingerprint only), and no shell, filesystem, or arbitrary code execution. What runs is inference on the models the Host chose to advertise.
- The Host's controls are which Circle it serves, which models it advertises, and when it is on (`saylek host pause`). Owner work takes priority over guest work on the Host's own machine, bounded rather than instant.
- Liability position: the sender is responsible for the content of a request. A Host serving in the ordinary way is not treated as the author or publisher of what passes through, because it cannot see or refuse a request on content. That protection covers serving only, not keeping copies, reading through what was served, publishing it, or running a modified build that logs it.
- Enforcement reaches accounts and routing, not machines: Saylek can suspend an account or stop routing, and cannot delete a request that already reached a Host.
- This page adds no obligation beyond the Terms of Service; it is the long form of terms sections 4, 6 and 7. Adding a duty would require a terms version bump, which re-prompts every member.

---

# Privacy (summary)

> SUMMARY ONLY. The canonical page is https://saylek.com/privacy (HTML, last
> reviewed 2026-07-24). Where this summary and that page differ, the page governs.

- Your prompts and uploads travel to a Circle-mate's machine when your own cannot serve them, and that machine reads them in the clear. TLS protects them in transit, not from the Host they travel to.
- The prompt also passes through Saylek's registry, which routes it.
- RETENTION, stated bluntly: nothing on a machine is ever deleted automatically. Receipts and logs on your machine and on a Host's persist until someone runs `saylek wipe`. There is no TTL and no cleanup job.
- The routing queue IS trimmed automatically, but by count (about 10,000 entries) and never by age, so there is no maximum time a prompt can sit in it. A quiet queue can hold it indefinitely.
- The completion coming BACK also passes through Saylek's registry, and is cleared once delivered, with a ten-minute backstop if delivery crashes. That is minutes, unlike the outbound queue.
- Receipts contain hashes, not prompt text, so they are not a transcript. Activity logs contain no prompt text either.
- Deleting an account is a 90-day SOFT delete: after 90 days it stops being recoverable, but the record is NOT purged or anonymised today. Do not describe the 90 days as a deletion window.
- Caveat: an opt-in `[debug] traces = true` setting writes prompts to a plaintext file. It is off by default, and a Circle-mate's request does not currently reach it, but that is incidental rather than a rule.
- Saylek does not train on your prompts, does not sell information about you, and does not read prompts for analytics or moderation.
- A Host sees a stable key fingerprint, not your name or email: pseudonymous, not anonymous. The registry does know which member you are.
- The controller is Saylek LLC, a Washington limited liability company. Outside parties handling data are Cloudflare (site, account records, bot check) and Resend (email delivery); everything else runs on Saylek's own servers or on a member's machine.
- Not yet settled, and named as outstanding on the page: the GDPR legal basis, whether Saylek is controller or processor for a routed request, and a minimum age.

---

# Security (summary)

> SUMMARY ONLY. The canonical page is https://saylek.com/security (HTML, last
> reviewed 2026-07-24). Where this summary and that page differ, the page governs.

- Every request produces a cryptographically signed receipt naming the machine that served it.
- Identity inside a Circle is email-blind; sign-in is passwordless, so there is no reusable password to phish or leak.
- Report a suspected vulnerability privately before disclosing it publicly; contact details are on the page.
