diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..dd4db6c
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,20 @@
+name: build
+
+on:
+ pull_request:
+ push:
+ branches: [main]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ cache: npm
+ - run: npm ci
+ - run: npm run types:check
+ - run: npm run check
+ - run: npm run build
diff --git a/.gitignore b/.gitignore
index 9e429e4..312cde8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,4 +23,6 @@ yarn-error.log*
# others
.env*.local
.vercel
-next-env.d.ts
\ No newline at end of file
+next-env.d.ts
+# local issue tracker (wayfinder map, never published)
+.scratch/
diff --git a/README.md b/README.md
index 9b7bba9..aadca86 100644
--- a/README.md
+++ b/README.md
@@ -1,45 +1,71 @@
-# docs
+# Solrouter docs
-This is a Next.js application generated with
-[Create Fumadocs](https://github.com/fuma-nama/fumadocs).
+Source for [docs.solrouter.com](https://docs.solrouter.com). Built with [Fumadocs](https://fumadocs.dev) on Next.js.
-Run development server:
+This repository is the source of truth for the public docs. Changes land through pull requests into `main`, and `main` deploys automatically. `scripts/publish-mirror.sh` is retired: it force-pushes a copy from the product monorepo and would erase merged pull requests.
+
+## Run it
```bash
-npm run dev
-# or
-pnpm dev
-# or
-yarn dev
+npm ci
+npm run dev # http://localhost:3000
+npm run build # production build
+npm run types:check # MDX collection, route types, tsc
+npm run check # prose, status, and diagram-fallback checks
+```
+
+## Layout
+
+```
+content/docs/ hand-written pages (MDX) and meta.json sidebars
+content/docs/api-reference/agent-privacy/
+ generated from openapi/agent-privacy.json, do not edit by hand
+openapi/agent-privacy.json snapshot of https://api.solrouter.com/agents/v1/openapi.json
+scripts/generate-openapi.mjs regenerates the Agent Privacy API pages from the snapshot
+scripts/check-docs.mjs the checks behind `npm run check`
+src/components/diagrams/ static, theme-aware diagrams (React + Tailwind)
+src/components/verify/ client widgets that call the live API
+src/lib/status.ts the status sentence shown under every page title
```
-Open http://localhost:3000 with your browser to see the result.
+The docs have two tiers. Start here, Products, and Account are written for readers with no technical background. Under the hood and Reference are written for engineers and auditors and cite the code that backs each claim.
+
+## Status policy
+
+Every hand-written page declares three frontmatter fields:
+
+```yaml
+status: live # live | soon | archived | mixed
+checked: "2026-08-26"
+statusNote: "Optional one-sentence reason for soon, archived, or mixed."
+```
-## Explore
+- Live: the code path exists and the surface answered on api.solrouter.com, npm, or solrouter.com on the `checked` date.
+- Soon: the code exists, but the surface is not published, not deployed, or not confirmed end to end.
+- Archived: removed or disabled. The page stays to explain the change.
+- Mixed: the page holds a table with a Status column. Read the rows.
-In the project, you can see:
+A feature nobody has confirmed ships as Soon, never as Live. The `checked` date changes only when someone re-checks the page against code or a live endpoint.
-- `lib/source.ts`: Code for content source adapter, [`loader()`](https://fumadocs.dev/docs/headless/source-api) provides the interface to access your content.
-- `lib/layout.shared.tsx`: Shared options for layouts, optional but preferred to keep.
+## Truth rule
-| Route | Description |
-| ------------------------- | ------------------------------------------------------ |
-| `app/(home)` | The route group for your landing page and other pages. |
-| `app/docs` | The documentation layout and pages. |
-| `app/api/search/route.ts` | The Route Handler for search. |
+Every product claim in a pull request cites a file path in the product code or a live response in the PR body. No number, name, date, or benchmark goes in without a source.
-### Fumadocs MDX
+## Diagrams
-A `source.config.ts` config file has been included, you can customise different options like frontmatter schema.
+Add a diagram as a React component under `src/components/diagrams/`. Give the root element `role="img"` and an `aria-label` that describes the whole picture in one sentence. In the MDX, follow the component with a short Markdown list titled **In words**. That list is what screen readers, `llms.txt`, and the `.md` routes see, because component markup carries no meaning there. `npm run check` fails when the list is missing.
-Read the [Introduction](https://fumadocs.dev/docs/mdx) for further details.
+## Writing rules
-## Learn More
+- Short sentences, about 20 words or fewer. One idea per sentence. Active voice.
+- No em dashes or en dashes. Use a period, a comma, a colon, or parentheses.
+- No filler vocabulary. `npm run check` lists the banned words.
+- Define a term in plain words before you use its acronym, or link to the glossary.
-To learn more about Next.js and Fumadocs, take a look at the following
-resources:
+## Pull request checklist
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js
- features and API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
-- [Fumadocs](https://fumadocs.dev) - learn about Fumadocs
+1. `npm run types:check`, `npm run check`, and `npm run build` pass.
+2. Every changed factual sentence cites a file path or a live response in the PR body.
+3. Touched pages have no horizontal scroll at 375 px. Wrap wide tables in a scroll container.
+4. Moved or renamed pages have a redirect row in `next.config.mjs`.
+5. No `Co-Authored-By` trailer in commits.
diff --git a/content/docs/api-reference/agent-privacy/managed-wallets/agents/v1/wallets/post.mdx b/content/docs/api-reference/agent-privacy/managed-wallets/agents/v1/wallets/post.mdx
index 500b9ea..6e8926a 100644
--- a/content/docs/api-reference/agent-privacy/managed-wallets/agents/v1/wallets/post.mdx
+++ b/content/docs/api-reference/agent-privacy/managed-wallets/agents/v1/wallets/post.mdx
@@ -2,7 +2,7 @@
title: Provision a managed Umbra wallet (Mode A)
description: >-
Create a Solrouter-custodied Umbra wallet. The keypair is generated
- server-side and envelope-encrypted (AES-256-GCM) — the agent never holds
+ server-side and envelope-encrypted (AES-256-GCM), so the agent never holds
private keys. Fund the returned `umbraAddress`, then run swaps and
encrypted-balance operations against the wallet id.
full: true
@@ -15,7 +15,7 @@ _openapi:
contents:
- content: >-
Create a Solrouter-custodied Umbra wallet. The keypair is generated
- server-side and envelope-encrypted (AES-256-GCM) — the agent never
+ server-side and envelope-encrypted (AES-256-GCM), so the agent never
holds private keys. Fund the returned `umbraAddress`, then run swaps
and encrypted-balance operations against the wallet id.
---
diff --git a/content/docs/api-reference/agent-privacy/private-balance/agents/v1/wallets/id/shield/post.mdx b/content/docs/api-reference/agent-privacy/private-balance/agents/v1/wallets/id/shield/post.mdx
index 8b1b5be..3041dd4 100644
--- a/content/docs/api-reference/agent-privacy/private-balance/agents/v1/wallets/id/shield/post.mdx
+++ b/content/docs/api-reference/agent-privacy/private-balance/agents/v1/wallets/id/shield/post.mdx
@@ -1,5 +1,5 @@
---
-title: Shield + unlink — mixer round-trip to a fresh address
+title: 'Shield + unlink: mixer round-trip to a fresh address'
description: >-
Four txs, ~60s. Public balance enters the Umbra mixer, a claim breaks the
on-chain link, then withdraw + transfer delivers to a FRESH destination.
diff --git a/content/docs/api-reference/agent-privacy/swaps/agents/v1/anonymity-set/get.mdx b/content/docs/api-reference/agent-privacy/swaps/agents/v1/anonymity-set/get.mdx
index 9f9cef4..4de1296 100644
--- a/content/docs/api-reference/agent-privacy/swaps/agents/v1/anonymity-set/get.mdx
+++ b/content/docs/api-reference/agent-privacy/swaps/agents/v1/anonymity-set/get.mdx
@@ -1,7 +1,7 @@
---
title: Pool depth for a denomination bucket
description: >-
- Inspect the anonymity set for a standard denomination bucket before swapping —
+ Inspect the anonymity set for a standard denomination bucket before swapping:
how many recent deposits share that bucket. A deeper pool means a larger crowd
to hide in.
full: true
@@ -14,7 +14,7 @@ _openapi:
contents:
- content: >-
Inspect the anonymity set for a standard denomination bucket before
- swapping — how many recent deposits share that bucket. A deeper pool
+ swapping: how many recent deposits share that bucket. A deeper pool
means a larger crowd to hide in.
---
diff --git a/content/docs/api-reference/agent-privacy/swaps/agents/v1/quote/get.mdx b/content/docs/api-reference/agent-privacy/swaps/agents/v1/quote/get.mdx
index 645fffc..4a0653d 100644
--- a/content/docs/api-reference/agent-privacy/swaps/agents/v1/quote/get.mdx
+++ b/content/docs/api-reference/agent-privacy/swaps/agents/v1/quote/get.mdx
@@ -2,7 +2,7 @@
title: Quote a private swap
description: >-
Price a private swap before executing it. Returns the expected output after
- Solrouter's spread plus anonymity-set guidance — whether the amount snaps to a
+ Solrouter's spread plus anonymity-set guidance: whether the amount snaps to a
standard denomination bucket (strong privacy) or is an off-bucket amount with
a unique on-chain fingerprint.
full: true
@@ -15,7 +15,7 @@ _openapi:
contents:
- content: >-
Price a private swap before executing it. Returns the expected output
- after Solrouter's spread plus anonymity-set guidance — whether the
+ after Solrouter's spread plus anonymity-set guidance: whether the
amount snaps to a standard denomination bucket (strong privacy) or is
an off-bucket amount with a unique on-chain fingerprint.
---
diff --git a/content/docs/api-reference/agent-privacy/swaps/agents/v1/swaps/oneshot/post.mdx b/content/docs/api-reference/agent-privacy/swaps/agents/v1/swaps/oneshot/post.mdx
index a18b97f..45edda0 100644
--- a/content/docs/api-reference/agent-privacy/swaps/agents/v1/swaps/oneshot/post.mdx
+++ b/content/docs/api-reference/agent-privacy/swaps/agents/v1/swaps/oneshot/post.mdx
@@ -1,7 +1,7 @@
---
title: Begin a one-shot ephemeral-wallet private swap (Mode B)
description: >-
- Start a private swap that runs through a throwaway ephemeral wallet — no
+ Start a private swap that runs through a throwaway ephemeral wallet, with no
managed custody. Solrouter returns an unsigned `fundingTx`; the agent signs
and broadcasts it, then calls `POST /swaps/oneshot/{id}/execute` to kick off
the swap orchestrator.
@@ -14,9 +14,9 @@ _openapi:
headings: []
contents:
- content: >-
- Start a private swap that runs through a throwaway ephemeral wallet —
- no managed custody. Solrouter returns an unsigned `fundingTx`; the
- agent signs and broadcasts it, then calls `POST
+ Start a private swap that runs through a throwaway ephemeral wallet,
+ with no managed custody. Solrouter returns an unsigned `fundingTx`;
+ the agent signs and broadcasts it, then calls `POST
/swaps/oneshot/{id}/execute` to kick off the swap orchestrator.
---
diff --git a/content/docs/api-reference/agent.mdx b/content/docs/api-reference/agent.mdx
index 99c2069..24a6fc1 100644
--- a/content/docs/api-reference/agent.mdx
+++ b/content/docs/api-reference/agent.mdx
@@ -1,12 +1,20 @@
---
title: "POST /agent"
icon: Webhook
-description: "The /agent endpoint runs your prompt through SERV guided reasoning with access to web search, on-chain data, DEX quotes, and Solana tools."
+description: "The /agent endpoint runs your prompt through a tool loop with web search, on-chain data, DEX quotes, and Solana tools. Optional guided reasoning (BRAID) and encrypted mode."
+status: live
+checked: "2026-08-26"
---
import { Callout } from 'fumadocs-ui/components/callout';
-The `/agent` endpoint runs your prompt through Solrouter's full SERV-guided agent pipeline. Unlike a direct chat completion, the agent has access to a suite of built-in tools — web search, on-chain data, DEX quotes, token prices, and more — and uses SERV (Structured Execution via Reasoning Virtualization) to walk a deterministic reasoning graph rather than letting the model make freeform structural decisions. The result is faster, cheaper, and more reliable than a standard agent loop, while still producing synthesis-quality answers for complex multi-step queries.
+The `/agent` endpoint runs your prompt through Solrouter's agent pipeline. Unlike a direct chat completion, the agent can call built-in tools: web search, on-chain data, DEX quotes, token prices, and more.
+
+The request body selects one of three paths.
+
+- Default: a standard tool loop with up to 8 model calls (`MAX_ITERATIONS = 8`).
+- `reasoning: 'braid'`: guided reasoning (BRAID). A fixed Guided Reasoning Diagram (GRD) collects data, then one synthesis call writes the reply. Older material calls this SERV.
+- `encryptedPrompt`: encrypted mode. The tool loop runs inside the CVM (a confidential virtual machine, which is a TEE, trusted execution environment) with a 5-tool allowlist.
## Endpoint
@@ -18,11 +26,15 @@ POST https://api.solrouter.com/agent
| Field | Type | Description |
| --- | --- | --- |
-| `prompt` | string (required) | The question or task you want the agent to work on. You can ask for research, comparisons, on-chain analysis, swap quotes, or any other task covered by the built-in tools. |
-| `model` | string | The model used for synthesis at the end of the reasoning pipeline. All models run on Solrouter's self-hosted Nosana GPU network — no third-party APIs. `gpt-oss:20b` (default) — Apache-2.0 open weights, 20B parameters. `qwen3:8b` — open weights, 8B parameters. |
-| `useTools` | boolean | Enable or disable tool calls during agent execution. When `true`, the agent can call any of its built-in tools to gather data before synthesising a final answer. Set to `false` to run the prompt through guided reasoning without external data retrieval. Defaults to `true`. |
+| `prompt` | string (required) | The question or task. Research, comparisons, on-chain analysis, swap quotes, or any task the built-in tools cover. |
+| `model` | string | The model that runs the loop and writes the reply. Models run on Nosana GPU nodes. `gpt-oss:20b` (default) is Live. `qwen3.8:27b` is Live. `gemma4:31b` is Soon. `qwen3:8b` is retired (Archived). A model with no configured Nosana endpoint returns 501 `nosana_not_configured`. |
+| `useTools` | boolean | Defaults to `true`. When `true`, the model can call any built-in tool before it writes the reply. Set `false` to run one plain completion with no tools. This field does not select guided reasoning. |
+| `chatId` | string | Optional conversation id. When present, the backend stores the turn in that chat's history and sends prior turns as context. When absent, the call is stateless. |
+| `reasoning` | string | Set `'braid'` to run guided reasoning instead of the tool loop. |
+| `braidOptions` | object | BRAID only. `includeTrace: true` adds `braidTrace` to the response. `forceGrdId` picks a GRD by id instead of intent detection. |
+| `encryptedPrompt` | string (JSON) | Encrypted mode. The prompt is encrypted client-side to the enclave public key and packaged as a JSON string with `ciphertext`, `nonce`, `publicKey`, `algorithm`, and `version`. The backend forwards it to the CVM without reading it. Status: Live for REST callers who send `encryptedPrompt`. Soon for the SDK. Not used by the chat app, whose agent mode runs the plaintext tool loop. |
-## Example Request
+## Example request
```bash
curl -X POST "https://api.solrouter.com/agent" \
@@ -35,39 +47,93 @@ curl -X POST "https://api.solrouter.com/agent" \
}'
```
-## Example Response
+## Example response (default path)
```json
{
"success": true,
"reply": "## Marginfi vs Kamino Lending Comparison\n\n...",
"toolCalls": [
- { "tool": "web_search", "args": { "query": "Marginfi vs Kamino lending Solana" } },
- { "tool": "token_price", "args": { "token": "MNDE" } }
+ { "tool": "web_search", "args": { "query": "Marginfi vs Kamino lending Solana" }, "result": { "...": "..." } },
+ { "tool": "token_price", "args": { "token": "MNDE" }, "result": { "...": "..." } }
],
+ "usage": { "promptTokens": 0, "completionTokens": 0, "totalTokens": 0 },
"iterations": 4,
- "skillGraph": {
- "nodesTraversed": ["defi-analysis", "liquidity-risk", "comparative-analysis"],
- "relevanceScore": 0.72
- }
+ "model": "gpt-oss:20b",
+ "provider": "nosana",
+ "billing": null,
+ "freeMessagesRemaining": 0
}
```
-## Response Fields
+## Response fields (default path)
| Field | Type | Description |
| --- | --- | --- |
-| `success` | boolean | Whether the request completed successfully. `true` on success; `false` if an error occurred. |
-| `reply` | string | The agent's final synthesised answer in Markdown. This is produced by the LLM synthesis step after SERV has collected all relevant data through tool calls. |
-| `toolCalls` | array | The list of tools the agent called during execution, in order. Each entry contains a `tool` name and an `args` object with the parameters that were passed to that tool. |
-| `iterations` | number | The number of reasoning iterations the SERV pipeline executed before producing the final answer. |
-| `skillGraph.nodesTraversed` | array | The skill graph nodes that were activated for this query. Nodes represent structured domain knowledge (e.g. `defi-analysis`, `liquidity-risk`, `comparative-analysis`) that was injected into the synthesis context. Simple queries may return an empty array if skill-graph traversal was skipped. |
-| `skillGraph.relevanceScore` | number | A score between 0 and 1 indicating how relevant the activated domain knowledge was to the query. Higher scores mean the skill graph contributed meaningfully to the final answer. |
+| `success` | boolean | `true` when the request completed. A caller with no free messages and no USDC balance gets HTTP 200 with `success: false`, `requiresDeposit: true`, and `reason: "free_trial_exhausted"`. |
+| `reply` | string | The final reply in Markdown. |
+| `toolCalls` | array | Every tool the agent called, in order. Each entry has `tool`, `args`, and `result`. |
+| `usage` | object | `promptTokens`, `completionTokens`, and `totalTokens`, summed over every model call in the loop. |
+| `iterations` | number | The number of model calls the loop made. At most 8. |
+| `model` | string | The model id that ran. |
+| `provider` | string | Always `"nosana"`. |
+| `billing` | object or null | The result of the billing step. `null` when billing failed or did not run. |
+| `freeMessagesRemaining` | number | Free messages left on the account after this call. |
+
+The response has no `skillGraph` field. The skill graph shapes the system prompt only.
+
+## Example response (BRAID path)
+
+```json
+{
+ "success": true,
+ "reply": "## Marginfi vs Kamino Lending Comparison\n\n...",
+ "reasoning": "braid",
+ "braidTrace": {
+ "grdId": "comparison",
+ "intent": "comparison",
+ "nodes": [
+ { "nodeId": "...", "label": "...", "type": "action", "status": "completed" }
+ ],
+ "totalDurationMs": 0,
+ "totalTokens": 0
+ },
+ "usage": { "promptTokens": 0, "completionTokens": 0, "totalTokens": 0 },
+ "iterations": 1,
+ "model": "gpt-oss:20b",
+ "provider": "nosana",
+ "cost": "FREE",
+ "freeMessagesRemaining": 0
+}
+```
+
+`braidTrace` is present only when `braidOptions.includeTrace` is `true`. On this path `iterations` counts GRD nodes, not model calls. If BRAID fails, the route falls back to the default tool loop.
+
+## Example response (encrypted mode)
+
+```json
+{
+ "success": true,
+ "encrypted": true,
+ "encryptedResponse": { "...": "..." },
+ "toolCallsCount": 2,
+ "attestation": { "...": "..." },
+ "privacyGuarantee": {
+ "backendSawPlaintext": false,
+ "toolsExecutedInTEE": true
+ },
+ "freeMessagesRemaining": 0
+}
+```
+
+The reply is encrypted to the `publicKey` inside `encryptedPrompt`. Any enclave error returns HTTP 500. The route does not fall back to a plaintext path.
+
+## Available tools
-## Available Tools
+The default path registers 18 tools. They are listed on the [Agent Framework](/docs/how-it-works/agent-reasoning) page: `web_search`, `scrape_url`, `crawl_url`, `solana_balance`, `token_price`, `swap_quote`, `trending_tokens`, `deepwiki`, `colosseum_search`, `colosseum_archives`, `paysh_search_apis`, `paysh_call_api`, `github_list_repos`, `github_issues`, `github_read_file`, `notion_search`, `notion_get_page`, and `notion_query_database`. The model picks the tools at each step of the loop.
-The agent has access to all built-in tools listed on the [Agents Overview](/docs/concepts/agent-framework) page, including `web_search`, `scrape_url`, `crawl_url`, `solana_balance`, `token_price`, `swap_quote`, `trending_tokens`, and `deepwiki`. Tool selection is handled automatically by the SERV reasoning pipeline — you don't need to specify which tools to use.
+Encrypted mode allows 5 tools inside the CVM: `web_search` (SearXNG inside the CVM), `token_price`, `trending_tokens`, `swap_quote`, and `solana_balance`.
- If you are using the `@solrouter/sdk`, you can reach the same SERV-guided agent pipeline by passing `reasoning: 'braid'` to `client.chat()`. This routes your request through `/agent` automatically and returns the same structured response, with the added benefit of client-side encryption if `encrypted: true` is set.
+ With `@solrouter/sdk` 1.1.0, `client.chat(prompt, { reasoning: 'braid' })` sends the request to `/agent`. The SDK sends the prompt in plaintext on this path and returns `encrypted: false`. The SDK does not send `encryptedPrompt` to `/agent`. Encrypted agent mode is Live over REST and Soon in the SDK.
diff --git a/content/docs/api-reference/authentication.mdx b/content/docs/api-reference/authentication.mdx
deleted file mode 100644
index 140f383..0000000
--- a/content/docs/api-reference/authentication.mdx
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "Authentication"
-icon: KeyRound
-description: "Pass your Solrouter API key as a Bearer token in the Authorization header. Generate keys at solrouter.com/sdk — no email or credit card required."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-
-Solrouter authenticates REST API requests using Bearer tokens. Every request you make must include your API key in the `Authorization` header. Keys are tied to a prepaid balance denominated in USDC or `$ROUTER`, and usage is metered per call — there are no subscriptions or seat fees.
-
-## Request Format
-
-Include your API key as a Bearer token in every request:
-
-```bash
-Authorization: Bearer sk_solrouter_...
-```
-
-## Getting an API Key
-
-1. Go to [solrouter.com/sdk](https://solrouter.com/sdk).
-2. Connect your Solana wallet — no email or credit card is required.
-3. Copy the generated API key. All keys follow the format `sk_solrouter_...`.
-4. Top up your balance in **USDC** or **`$ROUTER`** to start making calls.
-
-## Full Request Example
-
-The following `curl` command shows a complete authenticated request to the `/agent` endpoint:
-
-```bash
-curl -X POST "https://api.solrouter.com/agent" \
- -H "Authorization: Bearer sk_solrouter_..." \
- -H "Content-Type: application/json" \
- -d '{"prompt": "Hello", "model": "gpt-oss:20b", "useTools": false}'
-```
-
-## x402 Keyless Authentication
-
-If you are building an agent that does not hold an API key, Solrouter supports **x402 per-call USDC payment**. Instead of a long-lived API key, each request is settled individually on Solana mainnet via a Coinbase facilitator — no account or prepaid balance required.
-
-To discover the x402 payment manifest and per-call pricing, send a request to:
-
-```
-GET /.well-known/x402
-```
-
-Any x402-aware agent can use this manifest to self-fund calls autonomously. The x402 inference endpoint (`POST /api/v1/x402/chat/completions`) is Arcium-encrypted end-to-end and priced at \$0.005 per call.
-
-For agent-to-agent interoperability, Solrouter also publishes an A2A protocol v1.0 discovery card at:
-
-```
-GET /.well-known/agent-card.json
-```
-
-This card describes the full skill list available to agents integrating with the Solrouter Agent Privacy API.
-
-## Error Responses
-
-| Status | Meaning |
-| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| 401 Unauthorized | Missing or invalid API key. Check that your `Authorization` header is present and that the key begins with `sk_solrouter_`. |
-| 402 Payment Required | x402 payment is required, or your prepaid balance is insufficient. Top up at [solrouter.com/sdk](https://solrouter.com/sdk) or use x402 per-call settlement. |
-| 403 Forbidden | Your API key does not have permission to access this endpoint. |
-
-
- Never expose your API key in client-side code, public repositories, or browser bundles. If your key is compromised, anyone can drain your prepaid balance. Rotate it immediately at [solrouter.com/sdk](https://solrouter.com/sdk) and treat the new key as a secret environment variable on your server or in a secrets manager.
-
diff --git a/content/docs/api-reference/errors.mdx b/content/docs/api-reference/errors.mdx
new file mode 100644
index 0000000..ed9f548
--- /dev/null
+++ b/content/docs/api-reference/errors.mdx
@@ -0,0 +1,24 @@
+---
+title: "Errors"
+icon: TriangleAlert
+description: "The HTTP status codes the Solrouter API returns, what each one means, and how to fix it."
+status: live
+checked: "2026-08-26"
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+
+Every endpoint returns standard HTTP status codes. The common ones are below. Endpoint-specific errors are listed on each endpoint's reference page.
+
+| Status | Meaning | Fix |
+| --- | --- | --- |
+| `400` Bad Request | A required field is missing. The x402 and `/api/v1/chat/completions` routes require `encryptedPrompt` and `model`. | Send every required field. |
+| `401` Unauthorized | The `Authorization` header is missing, or the key does not begin with `sk_solrouter_`. | Send `Authorization: Bearer sk_solrouter_...`. |
+| `402` Payment Required | Your prepaid balance is empty, or the route is x402-paywalled and no payment was attached. | Top up at [solrouter.com/sdk](https://solrouter.com/sdk), or pay per call with x402 and retry. |
+| `403` Forbidden | Which endpoints return 403, and when, is not determined. The API-key check itself returns 401, not 403. | Not applicable. |
+| `502` TEE unreachable | The backend could not reach the enclave. | Retry. If it persists, the enclave is down. |
+| `503` TDX quote unavailable | The enclave is up but could not produce an attestation quote. | Retry. The reply path still works; only the quote is missing. |
+
+
+ Never expose your API key in client-side code or public repositories. Anyone with your key can spend your prepaid balance. If a key leaks, rotate it at [solrouter.com/sdk](https://solrouter.com/sdk).
+
diff --git a/content/docs/api-reference/meta.json b/content/docs/api-reference/meta.json
index 9dbaa4c..f193a78 100644
--- a/content/docs/api-reference/meta.json
+++ b/content/docs/api-reference/meta.json
@@ -1,11 +1,11 @@
{
- "title": "API Reference",
+ "title": "API",
"icon": "Terminal",
"pages": [
"overview",
- "authentication",
"agent",
"tee",
+ "errors",
"---Agent Privacy API---",
"agent-privacy/swaps",
"agent-privacy/managed-wallets",
diff --git a/content/docs/api-reference/overview.mdx b/content/docs/api-reference/overview.mdx
index 731c6ca..2675246 100644
--- a/content/docs/api-reference/overview.mdx
+++ b/content/docs/api-reference/overview.mdx
@@ -1,14 +1,21 @@
---
title: "Overview"
icon: List
-description: "The Solrouter REST API gives you encrypted AI chat, agent reasoning, TEE attestation, and private on-chain swaps. Base URL: https://api.solrouter.com"
+description: "The Solrouter REST API gives you encrypted chat completions, agent reasoning, TEE key and attestation reads, and private on-chain swaps. Base URL: https://api.solrouter.com"
+status: mixed
+checked: "2026-08-26"
+statusNote: "Chat, agent, and TEE endpoints are Live. Agent Privacy API swap execution is Soon."
---
import { Cards, Card } from 'fumadocs-ui/components/card';
import { Callout } from 'fumadocs-ui/components/callout';
import { MessageSquare, Bot, ShieldCheck, Lock } from 'lucide-react';
-The Solrouter REST API is the direct HTTP interface to Solrouter's cryptographically private AI infrastructure. You can use it to send encrypted chat completions, run SERV-guided agent reasoning with tool calls, verify TEE attestation, and orchestrate privacy-preserving on-chain swaps — all over a single authenticated surface without email, credit card, or KYC.
+The Solrouter REST API is the direct HTTP interface to Solrouter's private AI infrastructure. With it you can send encrypted chat completions and run agent reasoning with tool calls. You can also read the TEE (trusted execution environment) key and attestation quote. Private on-chain swaps use the same base URL. All of it sits on one authenticated surface with no email, credit card, or KYC.
+
+
+ Raw REST is plaintext unless you send `encryptedPrompt`. When you use `@solrouter/sdk`, chat requests are encrypted before they leave your machine, and the Solrouter backend relays the ciphertext to the TEE without reading it. If you call `POST /agent` with `curl` and a plain `prompt`, you are sending plaintext to the backend. `POST /tee/process` and `POST /api/v1/chat/completions` reject requests without `encryptedPrompt`.
+
## Base URL
@@ -20,31 +27,31 @@ https://api.solrouter.com
## Authentication
-All requests require a Bearer token in the `Authorization` header. You generate your key at [solrouter.com/sdk](https://solrouter.com/sdk) by connecting a Solana wallet — no email or credit card required. Balance is prepaid in USDC or `$ROUTER`.
+All requests require a Bearer token in the `Authorization` header. You generate your key at [solrouter.com/sdk](https://solrouter.com/sdk) by connecting a Solana wallet. No email or credit card is required. Balance is prepaid in USDC or `$ROUTER`.
```
Authorization: Bearer sk_solrouter_...
```
-For agents that don't hold an API key, Solrouter also supports **x402 per-call USDC payment** facilitated by Coinbase on Solana mainnet. See the [Authentication](/docs/api-reference/authentication) page for full details on both methods.
+For agents that do not hold an API key, Solrouter also supports **x402 per-call USDC payment** on Solana mainnet. The live manifest advertises Coinbase (`api.cdp.coinbase.com/x402`) as the facilitator. The manifest does not show which facilitator settles payments. See the [Authentication](/docs/build/api-key) page for full details on both methods.
## Endpoints
- } href="/docs/develop/privacy-sdk">
- Send end-to-end encrypted chat completions with **`@solrouter/sdk`** (encrypted client-side by default), or pay-per-call via the x402 `POST /api/v1/x402/chat/completions` endpoint in the Agent Privacy API below.
+ } href="/docs/build/privacy-sdk">
+ Status: Live. **POST /api/v1/chat/completions** takes an API key and requires `encryptedPrompt` and `model`; it returns 400 `bad_request` without them. `GET /api/v1/models`, `/api/v1/balance`, and `/api/v1/usage` sit beside it. `@solrouter/sdk` calls **POST /tee/process** and encrypts client-side. Keyless agents pay per call on `POST /api/v1/x402/chat/completions`.
} href="/docs/api-reference/agent">
- **POST /agent** — Run your prompt through the full SERV-guided agent pipeline with built-in tools including web search, on-chain data, DEX quotes, and Solana wallet inspection.
+ Status: Live. **POST /agent** runs your prompt through the tool-calling agent, with built-in tools for web search, on-chain data, DEX quotes, and Solana wallet inspection. Send `reasoning: 'braid'` for guided reasoning.
} href="/docs/api-reference/tee/public-key">
- **GET /tee/public-key** — Fetch the enclave's live X25519 public key, then verify it against the Intel-signed TDX attestation quote. See the [attestation guide](/docs/concepts/attestation) for the full verification flow.
+ Status: Live. **GET /tee/public-key** returns the enclave's live X25519 public key. **GET /tee/attestation** returns the TDX quote when the CVM can reach the dStack agent; otherwise `tdxQuote` is null and `tdxQuoteError` says why. See the [attestation guide](/docs/how-it-works/attestation) for the verification flow.
- } href="/docs/develop/private-swaps">
- **/agents/v1/**\* — Agent-first surface for private on-chain swaps, managed encrypted-balance wallets, and x402-paywalled encrypted inference. Full OpenAPI spec at `/agents/v1/openapi.json`.
+ } href="/docs/build/agent-privacy-api">
+ **/agents/v1/**\* is the agent-first surface for private on-chain swaps, managed wallets, and x402-paywalled encrypted inference. Discovery, quote, and anonymity-set reads are Live. Swap execution is Soon. Full OpenAPI spec at `/agents/v1/openapi.json`.
@@ -58,22 +65,20 @@ GET /agents/v1/openapi.json
You can import this spec directly into tools like Postman, Insomnia, or any OpenAPI-compatible client to explore all `/agents/v1/*` endpoints with type-safe request and response schemas.
-Two well-known discovery documents are also published for agent and payment interoperability:
+Two well-known discovery documents are also published for agent and payment interoperability. Both are served by the API host, `https://api.solrouter.com`.
```
-GET /.well-known/agent-card.json — A2A protocol v1.0 card with the full skill list
-GET /.well-known/x402 — x402 paywall manifest with per-call USDC pricing
+GET /.well-known/agent-card.json # A2A protocol v1.0 card with the full skill list
+GET /.well-known/x402 # x402 paywall manifest with per-call USDC pricing
```
## Response Format
-All endpoints return JSON. Every response includes a top-level `success` field that indicates whether the request completed without error:
+All endpoints return JSON. A top-level `success` field exists on `POST /agent` and `POST /tee/process` only:
-* `success: true` — the request succeeded; additional fields carry the result data.
-* `success: false` — the request failed; an `error` field describes what went wrong.
+* `success: true`: the request succeeded, and the other fields carry the result.
+* `success: false`: the request failed, and an `error` field names the failure.
-For a complete list of error codes and how to handle them, see the [Authentication](/docs/api-reference/authentication) page, which covers `401`, `402`, and `403` responses in detail.
+The TEE key and attestation reads, x402 inference, the discovery documents, and `/agents/v1` responses have no `success` field. They return the result object directly, or an `error` field with a non-2xx status.
-
- When you use the `@solrouter/sdk`, all chat requests are encrypted by default before leaving your machine. The Solrouter backend never sees plaintext — it routes the encrypted blob blindly to the Intel TDX enclave. If you call the REST API directly with `curl` or another HTTP client, you are sending plaintext unless you implement client-side encryption yourself or pass `"encrypted": false` intentionally.
-
+For error codes on authentication, see the [Authentication](/docs/build/api-key) page, which covers `401`, `402`, and `403` responses.
diff --git a/content/docs/api-reference/tee/public-key.mdx b/content/docs/api-reference/tee/public-key.mdx
index a5acce3..5016796 100644
--- a/content/docs/api-reference/tee/public-key.mdx
+++ b/content/docs/api-reference/tee/public-key.mdx
@@ -1,12 +1,14 @@
---
title: "GET /tee/public-key"
icon: KeyRound
-description: "Fetch the TDX enclave's X25519 public key for client-side encryption. The SDK fetches this automatically; required only for custom client implementations."
+description: "Fetch the enclave's X25519 public key for client-side encryption. The SDK fetches it once per process and caches it. Call it yourself only in a custom client."
+status: live
+checked: "2026-08-26"
---
import { Callout } from 'fumadocs-ui/components/callout';
-This endpoint returns the X25519 public key that is currently active inside the Solrouter Intel TDX enclave. Before sending a prompt or payload, your client uses this key to encrypt the data with Arcium's RescueCipher so that only the enclave can decrypt it. The Solrouter backend receives an opaque ciphertext blob and routes it to the enclave without being able to read its contents.
+This endpoint returns the X25519 public key that is active inside the Solrouter Intel TDX enclave (a TEE, a trusted execution environment: a hardware-isolated virtual machine). Before you send a prompt, your client encrypts it to this key with Arcium's RescueCipher. Only the enclave can decrypt it. The Solrouter backend receives an opaque ciphertext blob and relays it to the enclave. It cannot read the contents.
## Endpoint
@@ -14,14 +16,18 @@ This endpoint returns the X25519 public key that is currently active inside the
GET https://api.solrouter.com/tee/public-key
```
-No authentication is required for this endpoint.
+No authentication is required for this endpoint. The backend proxies the call to the enclave and returns the enclave's body unchanged.
## Response
| Field | Type | Description |
| --- | --- | --- |
-| publicKey | string | The enclave's current X25519 public key, encoded in base64. Use this as the recipient key when performing client-side encryption. |
-| algorithm | string | The key exchange algorithm. Always `X25519`. |
+| publicKey | string | The enclave's current X25519 public key, base64 encoded. Use it as the recipient key for client-side encryption. |
+| publicKeySha256 | string | Hex sha256 of the raw 32-byte public key. `GET /tee/attestation` pins this same digest in the quote's `report_data`. |
+| algorithm | string | Always `x25519` (lower case). |
+| teeType | string | Always `INTEL-TDX-PHALA`. |
+
+This response has no top-level `success` field.
## Example
@@ -29,25 +35,41 @@ No authentication is required for this endpoint.
curl "https://api.solrouter.com/tee/public-key"
```
-Example response:
+Example response (shape checked against the live endpoint on 2026-08-26; values shortened):
```json
{
- "publicKey": "abc123...base64encodedkey...==",
- "algorithm": "X25519"
+ "publicKey": "base64...=",
+ "publicKeySha256": "hex...",
+ "algorithm": "x25519",
+ "teeType": "INTEL-TDX-PHALA"
+}
+```
+
+## Errors
+
+When the backend cannot reach the enclave, it answers with status 502 and this body:
+
+```json
+{
+ "error": "tee_unreachable",
+ "message": "...",
+ "teeEndpoint": "..."
}
```
## When to use this
-In most cases, you do not need to call this endpoint directly:
+In most cases you do not need to call this endpoint yourself.
+
+* **`@solrouter/sdk`**: the SDK fetches the key once per process and caches it. You never handle the key yourself.
+* **`@solrouter/agent-tools`** (Soon): the package is not on npm yet.
+* **Custom client**: if you write your own encryption layer (for example in a language with no Solrouter SDK), fetch this endpoint first. Then use `publicKey` as the X25519 recipient key in your RescueCipher key-exchange flow.
-* **Using the `@solrouter/sdk`** — the SDK fetches the TEE public key automatically before every encrypted request. You never handle the key yourself.
-* **Using the `@solrouter/agent-tools` SDK** — same behavior; key fetch and encryption are handled transparently.
-* **Building a custom client** — if you are implementing your own encryption layer (for example, in a language without an official Solrouter SDK), fetch this endpoint first, then use the returned key as the X25519 recipient public key in your RescueCipher / ECDH key-exchange flow.
+## Key lifetime and caching
-The SDK always fetches a fresh key before each session rather than caching a previously retrieved key. You should follow the same practice in custom clients to ensure you are always encrypting to the currently active enclave key.
+The enclave generates a new X25519 keypair on every CVM boot. The SDK fetches the key once per process and keeps it until you call `clearSession()`. A long-lived process can hold a stale key after the enclave restarts. When a request fails with `tee_unreachable`, or a reply fails to decrypt, call `clearSession()` and retry. The next request fetches the current key. Custom clients should do the same: cache the key, and fetch it again after a failure.
- The X25519 keypair is generated inside the Confidential VM at boot time. The private key never leaves the enclave — not to the Solrouter backend, not to any host process, and not to Solrouter employees. You can verify this claim independently by checking the TDX attestation quote, which binds the public key to the exact code measurement running inside the enclave — see the [attestation verification guide](/docs/concepts/attestation).
+ The X25519 keypair is generated inside the Confidential VM at boot. The private key never leaves the enclave: not to the Solrouter backend, not to any host process, and not to Solrouter staff. You can check this claim yourself. `GET /tee/attestation` returns a TDX quote whose `report_data` equals `sha256(publicKey)`. See the [attestation guide](/docs/how-it-works/attestation).
diff --git a/content/docs/build/agent-privacy-api.mdx b/content/docs/build/agent-privacy-api.mdx
new file mode 100644
index 0000000..0e9501b
--- /dev/null
+++ b/content/docs/build/agent-privacy-api.mdx
@@ -0,0 +1,142 @@
+---
+title: "Agent Privacy API"
+icon: ArrowRightLeft
+description: "The Agent Privacy API (/agents/v1) gives AI agents private token swaps on Solana in two modes, plus pay-per-call encrypted inference over x402."
+status: mixed
+checked: "2026-08-26"
+statusNote: "Swap execution is Soon: no mainnet swap run is on record. Discovery, quote, and anonymity-set reads are Live."
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
+
+When an agent moves tokens on Solana, the transaction graph shows who paid whom. Anyone can trace the funding source to the destination. The Agent Privacy API (`/agents/v1`) breaks that link. It serves two agent needs: private on-chain swaps and encrypted inference. The main Solrouter SDK covers encrypted chat and research. One agent type swaps tokens privately. The other has no API key and pays per inference call with x402, a pay-per-request HTTP standard. The Solrouter backend and a swap worker run the swaps. The TEE (trusted execution environment, a hardware-isolated enclave) does not. Only the x402 inference endpoint on this page uses the encrypted TEE path.
+
+No sanctions screening runs today. Agents are responsible for their own compliance.
+
+## Feature status
+
+| Feature | Status |
+| --- | --- |
+| Discovery documents (`/.well-known/*`, `/agents/v1/openapi.json`, `/agents/v1/capabilities`) | Live |
+| `GET /agents/v1/quote` and `GET /agents/v1/anonymity-set` | Live |
+| Mode A managed-wallet swaps | Soon |
+| Mode B one-shot swaps | Soon |
+| `POST /api/v1/x402/chat/completions` | Live |
+| `@solrouter/agent-tools` npm package | Soon |
+
+## Execution modes
+
+Pick a mode by one question: does your agent keep a funded wallet with Solrouter, or sign each operation on the fly? The API supports both.
+
+Both swap modes are Soon. The code path exists, but no mainnet swap run is on record as of 2026-08-26. The samples below show the request shapes the routes accept today.
+
+
+
+ Fund once and forget the setup. Your agent provisions a long-lived managed Umbra wallet through the API, funds it once, then runs as many private swaps as it needs. Use it for agents that swap often, accumulate balance, or run on a schedule. Wallet routes require an API key.
+
+ **How custody works:**
+
+ * Solrouter holds the wallet keypair. The per-wallet Data Encryption Key (DEK) is wrapped with a Key Encryption Key (KEK) that the backend reads from `WALLET_VAULT_KEK`.
+ * The DEK is unwrapped inside the backend API and the swap worker for one operation, then wiped.
+ * The wallet vault runs in the backend process, not inside a TEE.
+
+ ```bash
+ # Provision a managed wallet for this agent
+ curl -X POST "https://api.solrouter.com/agents/v1/wallets" \
+ -H "Authorization: Bearer sk_solrouter_..." \
+ -H "Content-Type: application/json" \
+ -d '{}'
+ # -> { "walletId": "...", "umbraAddress": "...", "network": "mainnet", "fundingHint": "..." }
+
+ # Fund umbraAddress, then run a swap from the managed wallet
+ curl -X POST "https://api.solrouter.com/agents/v1/wallets/WALLET_ID/swap" \
+ -H "Authorization: Bearer sk_solrouter_..." \
+ -H "Content-Type: application/json" \
+ -d '{
+ "fromMint": "So11111111111111111111111111111111111111112",
+ "toMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
+ "amount": "10000000",
+ "destinationPubkey": "YOUR_FRESH_DESTINATION_ADDRESS"
+ }'
+ # -> { "sessionId": "...", "status": "running", "estimatedSeconds": 70 }
+ ```
+
+
+
+ Use this mode when your agent has its own wallet and holds no balance with Solrouter. Nothing is provisioned. Your agent gets an unsigned funding transaction, signs it, submits the signature, and the worker handles the rest. Good for stateless agents and single-operation workflows.
+
+ **The 7-step pipeline:**
+
+ 1. Agent requests a one-shot session with payer pubkey, mints, amount, and destination
+ 2. API returns an unsigned funding transaction
+ 3. Agent signs the transaction with its own wallet and broadcasts it
+ 4. Agent submits the transaction signature to the API to start execution
+ 5. Worker runs the Umbra mixer round-trip to break the on-chain link
+ 6. Jupiter aggregator executes the swap
+ 7. Worker forwards the proceeds to the destination, with no on-chain link to the payer
+
+ ```bash
+ # 1. Create the session
+ curl -X POST "https://api.solrouter.com/agents/v1/swaps/oneshot" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "payerPubkey": "YOUR_AGENT_WALLET_PUBKEY",
+ "fromMint": "So11111111111111111111111111111111111111112",
+ "toMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
+ "amount": "10000000",
+ "destinationPubkey": "FRESH_DESTINATION_ADDRESS"
+ }'
+ # -> { "sessionId": "...", "ephemeralPubkey": "...", "fundingTx": "", "expectedSeconds": 75, ... }
+
+ # 2. Sign fundingTx with your wallet and broadcast it.
+ # 3. Submit the confirmed signature:
+ curl -X POST "https://api.solrouter.com/agents/v1/swaps/oneshot/SESSION_ID/execute" \
+ -H "Content-Type: application/json" \
+ -d '{"fundingTxSig": "..."}'
+
+ # 4. Poll until state is settled
+ curl "https://api.solrouter.com/agents/v1/sessions/SESSION_ID"
+ ```
+
+
+
+**What Solrouter stores per session:** `from_mint`, `to_mint`, `amount_base_units`, `destination_pubkey`, `payer_user_id`, `ephemeral_pubkey`, the wrapped ephemeral key, `final_tx_sig`, and `actual_out`. Solrouter's backend can read every column. Retention period: not published.
+
+## Discovery endpoints
+
+So your agent does not hardcode URLs, the API publishes its own configuration. A2A-compatible agents (the Agent-to-Agent interop protocol) and x402-aware runtimes read these endpoints to self-configure at runtime.
+
+| Endpoint | Description | Status |
+| ------------------------------ | ----------------------------------------------------------------- | ------ |
+| `/.well-known/agent-card.json` | A2A protocol v1.0 card with the full skill list | Live |
+| `/.well-known/x402` | x402 paywall manifest: per-call USDC pricing for keyless agents | Live |
+| `/agents/v1/openapi.json` | Full OpenAPI 3.1 specification | Live |
+| `/agents/v1/capabilities` | Capability summary for runtime introspection | Live |
+
+The manifest is served by the API host: `https://api.solrouter.com/.well-known/x402`.
+
+## x402 encrypted inference
+
+Not every agent has an API key, and account creation is friction. For those cases Solrouter exposes a pay-per-call encrypted inference endpoint. Your agent pays in USDC on Solana mainnet, with no account and no key management. x402 is the standard. The live manifest advertises Coinbase (`api.cdp.coinbase.com/x402`) as the facilitator. The manifest shows `X402_FACILITATOR_URL` when set, or a built-in default when not. It does not show which facilitator settles payments. pay.sh is a catalog that lists the endpoint.
+
+* **Endpoint:** `POST /api/v1/x402/chat/completions`
+* **Pricing:** \$0.005 per call, settled via x402 USDC on Solana mainnet
+* **Encryption:** Arcium-encrypted prompt in, encrypted response out. The same TEE path as the SDK.
+* **Discovery:** `/.well-known/x402`. Any x402-aware runtime can auto-discover pricing and payment instructions.
+
+```bash
+# x402 paywalled encrypted inference. No API key needed.
+# `encryptedPrompt` MUST be an Arcium ciphertext produced client-side.
+# Use encrypt(message, baseUrl) and packageForTEE(encryptedData) from @solrouter/sdk.
+# `model` is required.
+curl -X POST "https://api.solrouter.com/api/v1/x402/chat/completions" \
+ -H "Content-Type: application/json" \
+ -d '{"encryptedPrompt": "", "model": "gpt-oss:20b"}'
+```
+
+Call the endpoint without payment and the server replies `402 Payment Required` with the price, the network, and the `payTo` address. An x402-aware runtime signs a USDC payment payload with the agent's wallet key and retries with the `X-PAYMENT` header. Solrouter's server sends that payload to its facilitator to verify and settle the transfer, then returns 200. The agent never talks to the facilitator.
+
+The paywall charges \$0.005 per call. The response body currently reports `paid.amount: 0.02`. This is a backend follow-up; the manifest price is the one charged.
+
+This endpoint returns the encrypted reply only. It does not commit an on-chain receipt. Receipts are created for `POST /tee/process`, the route the SDK uses. See [Encryption Proof](/docs/how-it-works/proof).
diff --git a/content/docs/build/agent-tools-sdk.mdx b/content/docs/build/agent-tools-sdk.mdx
new file mode 100644
index 0000000..ff16267
--- /dev/null
+++ b/content/docs/build/agent-tools-sdk.mdx
@@ -0,0 +1,95 @@
+---
+title: "Agent Tools SDK"
+icon: Bot
+description: "Typed tools for the Solrouter Agent Privacy API with a Vercel AI SDK adapter. The package is not on npm yet. Use the HTTP API or the MCP tools today."
+status: soon
+checked: "2026-08-26"
+statusNote: "The @solrouter/agent-tools package is not on npm yet."
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+
+
+ `@solrouter/agent-tools` is not published on npm. The package exists in the Solrouter repository at version 1.0.0, but you cannot install it today. The code samples on this page show the planned API. To use the Agent Privacy API now, call `POST /agents/v1/*` over HTTP or use the `umbra_*` tools in the [MCP server](/docs/build/mcp-server).
+
+
+An AI agent that swaps tokens on Solana leaves a link from payer to destination. To break that link you normally wire up quoting, signing, mixing, and settlement yourself. `@solrouter/agent-tools` will do that work. It gives your agent typed tools for the Agent Privacy API (`/agents/v1`). The agent can quote, run, and settle private swaps, and call encrypted inference.
+
+It ships with a Vercel AI SDK adapter, so you can drop it into an agent without an orchestration layer. Not on the AI SDK? The raw `TOOLS` (JSON Schema definitions) and the `callTool()` function are also exported, so any function-calling framework works.
+
+## What to use today
+
+- **HTTP.** Call the Agent Privacy API directly. Quotes and anonymity-set reads are live at `GET /agents/v1/quote` and `GET /agents/v1/anonymity-set`. Swap execution routes are Soon.
+- **MCP.** The [MCP server](/docs/build/mcp-server) wraps the same routes as `umbra_*` tools for Claude Desktop and Cursor.
+
+## Vercel AI SDK quickstart (Soon)
+
+This will be the fastest path: let an LLM decide when to swap, and let the adapter handle the plumbing. Pass `aiSdkTools(solrouter)` into `generateText` or `streamText`. The adapter wires up the tool schemas, validates the model's arguments, and returns results to the model.
+
+```typescript
+import { generateText } from "ai";
+import { SolrouterAgentClient } from "@solrouter/agent-tools";
+import { aiSdkTools } from "@solrouter/agent-tools/ai-sdk";
+
+const solrouter = new SolrouterAgentClient({
+ apiKey: process.env.SOLROUTER_API_KEY,
+});
+
+const result = await generateText({
+ model: yourModel, // any AI SDK model provider
+ tools: aiSdkTools(solrouter),
+ prompt: "Privately swap 0.01 SOL to USDC and send the USDC to AAA...XXX",
+});
+```
+
+## Direct usage, no LLM (Soon)
+
+Sometimes you do not want a model in the loop. You want to drive the privacy pipeline yourself in code. Mode B one-shot swaps do that. Your agent signs the funding transaction with its own wallet. Solrouter then runs the mixer round trip, the Jupiter swap, and the forward to the destination.
+
+```typescript
+import { SolrouterAgentClient } from "@solrouter/agent-tools";
+
+const client = new SolrouterAgentClient({ apiKey: "sk_solrouter_..." });
+
+const session = await client.swapOneshot({
+ payerPubkey: "...",
+ fromMint: "So11111111111111111111111111111111111111112", // SOL
+ toMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
+ amount: "10000000",
+ destinationPubkey: "...", // use a fresh address
+});
+
+// Sign session.fundingTx with your wallet, broadcast, then:
+await client.swapOneshotExecute(session.sessionId, fundingTxSig);
+const settled = await client.pollUntilSettled(session.sessionId);
+```
+
+## Authentication modes
+
+How your agent proves it can pay shapes how you deploy it, so pick the mode that fits before you build. The Agent Privacy API supports two.
+
+* **API key.** Include `Authorization: Bearer sk_solrouter_...` in every request. Usage bills against your prepaid balance in USDC or `$ROUTER`. Best when your agent is long-lived and you have already funded an account.
+* **x402 (keyless).** Pay per call in USDC on Solana mainnet through an x402 facilitator, with no account at all. The live manifest advertises Coinbase (`api.cdp.coinbase.com/x402`). The manifest shows `X402_FACILITATOR_URL` when it is set, or a built-in default when it is not. It does not show which facilitator settles payments. Discover pricing and payment endpoints at [`/.well-known/x402`](https://api.solrouter.com/.well-known/x402).
+
+
+ x402 fits agents that run without a pre-registered API key, for example autonomous agents that start on demand and pay for exactly the calls they make. No balance top-up or account creation is required. The agent still holds a wallet private key to sign payments.
+
+
+## Available tools
+
+These are the building blocks your agent will call, through `aiSdkTools()` or the raw `TOOLS` / `callTool()` exports. Each one maps to one step of the private-swap or encrypted-inference flow. The Status column describes the API route behind the tool, not the package.
+
+| Tool | Description | Status |
+| ---------------------------- | ------------------------------------------------------------------------------------ | ------ |
+| `umbra_quote` | Quote a private swap with anonymity-set sizing | Live |
+| `umbra_anonymity_set` | Inspect the current anonymity set for a mint pair | Live |
+| `umbra_swap_oneshot` | Open a one-shot swap session. The agent signs the funding transaction | Soon |
+| `umbra_swap_oneshot_execute` | Submit the signed funding transaction to start execution | Soon |
+| `umbra_session_status` | Poll session state until `settled` | Soon |
+| `umbra_create_wallet` | Provision a managed wallet for an agent | Soon |
+| `umbra_swap_managed` | Run a swap from a managed wallet | Soon |
+| `umbra_encrypt` | Convert a balance to an encrypted balance on the same wallet | Soon |
+| `umbra_shield` | Mixer round trip, withdraw, then forward to a fresh address | Soon |
+| `umbra_balance` | Read the encrypted balance of a managed wallet | Soon |
+| `umbra_attestation` | Read the settlement record of a swap session (`GET /agents/v1/attestations/:sessionId`) | Soon |
+| `private_inference_paid` | x402-paywalled encrypted inference, no API key | Live |
diff --git a/content/docs/build/api-key.mdx b/content/docs/build/api-key.mdx
new file mode 100644
index 0000000..2b0f9c5
--- /dev/null
+++ b/content/docs/build/api-key.mdx
@@ -0,0 +1,106 @@
+---
+title: "Get an API key"
+icon: KeyRound
+description: "Get an API key by connecting a Solana wallet at solrouter.com/sdk. No email, no KYC. Send the key as a bearer token, or pay per call with x402."
+status: live
+checked: "2026-08-26"
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+import { Step, Steps } from 'fumadocs-ui/components/steps';
+
+Most AI APIs make you sign up with an email, verify your identity, and add a credit card before your first request. Solrouter skips all of that. You authenticate with an API key sent as a bearer token. You get that key by connecting a Solana wallet. There is no email sign-up, no KYC (Know Your Customer identity check), and no card.
+
+Fund a prepaid balance in USDC or \$ROUTER, and you can make calls in minutes.
+
+## Getting your API key
+
+Here is the full path from zero to your first authenticated request. It has four steps, all in the browser.
+
+
+
+### Go to solrouter.com/sdk
+
+Open [solrouter.com/sdk](https://solrouter.com/sdk) in your browser.
+
+
+
+### Connect your Solana wallet
+
+Connect Phantom, Solflare, or a Privy embedded wallet (any Wallet Standard wallet). Your wallet is your only identity credential. Solrouter collects no email and no personal information.
+
+
+
+### Generate an API key
+
+Click **Generate API Key**. Your key is issued at once and starts with `sk_solrouter_...`. Copy it and store it somewhere safe. It is not shown again.
+
+
+
+### Top up your balance
+
+Add funds to your prepaid account in **USDC** or **\$ROUTER**. Solrouter meters every API call and deducts the cost from this balance. There is no monthly bill. You pay only for what you use.
+
+
+
+## Using your API key
+
+Once you have a key, you attach it to requests in one of two ways: through the SDK, which handles it for you, or directly over HTTP.
+
+### With the SDK
+
+Pass your API key when you create the `SolRouter` client. From then on, the SDK attaches it to every request. You never touch the header yourself.
+
+```typescript
+import { SolRouter } from '@solrouter/sdk';
+
+const client = new SolRouter({
+ apiKey: 'sk_solrouter_...',
+ baseUrl: 'https://api.solrouter.com',
+});
+```
+
+### Direct HTTP (REST API)
+
+If you are not using the SDK, send the key yourself as a bearer token in the `Authorization` header.
+
+```bash
+curl -X POST "https://api.solrouter.com/agent" \
+ -H "Authorization: Bearer sk_solrouter_..." \
+ -H "Content-Type: application/json" \
+ -d '{"prompt": "Hello", "model": "gpt-oss:20b"}'
+```
+
+## Authentication tiers
+
+External callers have two ways to authenticate. Pick the row that matches how your code runs.
+
+| Tier | How it works | Best for |
+| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
+| **API key** | `Authorization: Bearer sk_solrouter_...`, billed from your prepaid balance | Most applications and development workflows |
+| **x402 (keyless)** | Per-call USDC settlement on Solana mainnet | Autonomous agents that do not hold API keys |
+
+x402 settles through a facilitator. The live manifest advertises Coinbase (`api.cdp.coinbase.com/x402`). Service discovery is at [`/.well-known/x402`](https://api.solrouter.com/.well-known/x402). The manifest shows `X402_FACILITATOR_URL` when it is set, or a built-in default when it is not. The manifest does not show which facilitator settles payments. Wire-level facilitator: not determined.
+
+The x402 tier is worth a closer look if you build agents. Instead of storing a long-lived key, an agent pays for each call on the spot in USDC. x402 removes the API key, not the wallet key. The agent still holds a wallet private key to sign payments, so protect that key the same way.
+
+## Keeping your API key safe
+
+Your key can spend real money, so treat it with the same care as a password. The practices below keep it out of the wrong hands.
+
+* **Never commit your API key to source control.** Treat `sk_solrouter_...` like a password. Keep it out of Git history, checked-in `.env` files, and any public repository.
+
+* **Use environment variables.** Store your key in `SOLROUTER_API_KEY` and read it at runtime, so the secret never lives in your code:
+
+ ```typescript
+ const client = new SolRouter({
+ apiKey: process.env.SOLROUTER_API_KEY,
+ baseUrl: 'https://api.solrouter.com',
+ });
+ ```
+
+* **Rotate compromised keys at once.** If a key is exposed, go to [solrouter.com/sdk](https://solrouter.com/sdk), delete the affected key, and generate a new one.
+
+
+ Never expose your API key in client-side code or public repositories. Anyone with your key can spend your prepaid balance. If you suspect a key has leaked, rotate it at once at solrouter.com/sdk.
+
diff --git a/content/docs/build/mcp-server.mdx b/content/docs/build/mcp-server.mdx
new file mode 100644
index 0000000..2ce9a7c
--- /dev/null
+++ b/content/docs/build/mcp-server.mdx
@@ -0,0 +1,86 @@
+---
+title: "MCP Server"
+icon: Plug
+description: "Use Solrouter's encrypted chat and Agent Privacy API tools from Claude Desktop or Cursor with @solrouter/mcp-server. Some tool calls leave your machine in plaintext."
+status: mixed
+checked: "2026-08-26"
+statusNote: "The server is on npm. Encrypted chat is live. Swap execution tools are Soon. Read the status word beside each tool."
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+
+You already work inside Claude Desktop or Cursor. The Solrouter MCP server lets you run Solrouter's encrypted chat and Agent Privacy API tools right there. You need no separate app.
+
+MCP (Model Context Protocol, an open standard for connecting AI clients to external tools) is the bridge. The server runs on your machine as `npx @solrouter/mcp-server`. It holds your API key and encrypts prompts for the `encrypted_chat` tool and for the AI synthesis step of the research tools. Other calls leave your machine in plaintext. The tables below say which.
+
+## Configuration
+
+This is the one-time setup that registers Solrouter as a tool provider in your client.
+
+Add the following block to your MCP configuration file. For **Claude Desktop**, that file is `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS (or the equivalent path on Windows). For **Cursor**, add it under `mcpServers` in `~/.cursor/mcp.json`.
+
+```json
+{
+ "mcpServers": {
+ "solrouter": {
+ "command": "npx",
+ "args": ["@solrouter/mcp-server"],
+ "env": {
+ "SOLROUTER_API_KEY": "sk_solrouter_...",
+ "SOLROUTER_API_URL": "https://api.solrouter.com"
+ }
+ }
+ }
+}
+```
+
+Set `SOLROUTER_API_URL`. Without it, the server defaults to a Render host, not `api.solrouter.com`. Set `BRAVE_API_KEY` too: `private_research` and `private_token_analysis` fail without it. `HELIUS_RPC_URL` is optional (default: `https://api.mainnet-beta.solana.com`).
+
+Save the config, then restart Claude Desktop or reload the Cursor window. The Solrouter tools appear in the tool list. There is nothing else to install.
+
+## Privacy and research tools
+
+Use these tools for encrypted AI inference or on-chain research from inside your client. Only the AI step is encrypted. The data-gathering steps call third parties directly from your machine in plaintext.
+
+| Tool | Description | Leaves your machine in plaintext |
+| --- | --- | --- |
+| `encrypted_chat` (Live) | Encrypted AI query through `/tee/process` | Nothing. The prompt is encrypted on your machine |
+| `private_research` (Live) | Web search, DEX data, and on-chain lookups, then an encrypted AI synthesis | Query to Brave; token symbols to DexScreener; wallet addresses to the Solana RPC |
+| `private_token_analysis` (Live) | DEX data, price, and web results for one token, then an encrypted AI synthesis | The token to DexScreener, CoinGecko, and Brave |
+| `private_wallet_audit` (Live) | Holdings of one wallet, then an encrypted AI synthesis | The wallet address to the Solana RPC and DexScreener |
+| `list_models` (Live) | Models from `GET /api/v1/models` with pricing | Nothing sensitive |
+| `account_balance` (Live) | Your credit balance from `GET /api/v1/balance` | Nothing sensitive |
+
+## Agent and swap helper tools
+
+These tools call the Solrouter backend in plaintext or return text without any network call.
+
+| Tool | Description | Leaves your machine in plaintext |
+| --- | --- | --- |
+| `agent_run` (Live) | Tool-augmented agent completion through `POST /agent` (web search, Solana data, paid APIs) | Your prompt, to the Solrouter backend |
+| `umbra_describe` (Live) | Explains private swaps. Makes no network call | Nothing |
+| `umbra_anonymity_stats` (Soon) | Deposit count for one denomination bucket from `GET /umbra/anonymity-set` | The bucket and network |
+| `umbra_initiate_private_swap_widget` (Soon) | Returns a directive that tells the Solrouter web chat to show the swap widget. Executes nothing | Suggested tokens and network |
+
+## Agent Privacy API tools
+
+These tools wrap `POST` and `GET /agents/v1/*` over HTTPS with your API key. Swap parameters travel in plaintext to the Solrouter backend. Swap execution is Soon. Tools marked Soon can move real funds once they go live, so read the session state before you act on it.
+
+| Tool | Description |
+| --- | --- |
+| `umbra_quote` (Live) | Quote a private swap with anonymity-set sizing |
+| `umbra_anonymity_set` (Live) | Inspect the current anonymity set for a mint pair |
+| `umbra_swap_oneshot` (Soon) | Open a one-shot swap session. The agent signs the funding transaction |
+| `umbra_swap_oneshot_execute` (Soon) | Submit the signed funding transaction to start execution |
+| `umbra_session_status` (Soon) | Poll session state until `settled` |
+| `umbra_create_wallet` (Soon) | Provision a managed wallet for an agent |
+| `umbra_swap_managed` (Soon) | Run a swap from a managed wallet |
+| `umbra_encrypt` (Soon) | Convert a balance to an encrypted balance on the same wallet |
+| `umbra_shield` (Soon) | Mixer round trip, withdraw, then forward to a fresh address |
+| `umbra_balance` (Soon) | Read the encrypted balance of a managed wallet |
+| `umbra_attestation` (Soon) | Read the settlement record of a swap session (`GET /agents/v1/attestations/:sessionId`) |
+| `private_inference_paid` (Live) | x402-paywalled encrypted inference, no API key. You supply the encrypted prompt yourself |
+
+
+ Not every request through the MCP server is encrypted. `encrypted_chat` and the AI synthesis step of the three research tools use the Privacy SDK path: RescueCipher and Intel TDX. The Solrouter backend never sees that plaintext. Web search (Brave), DexScreener, CoinGecko, and Solana RPC lookups go from your machine to those third parties in plaintext. `agent_run` and the `umbra_*` tools send their inputs to the Solrouter backend in plaintext.
+
diff --git a/content/docs/develop/meta.json b/content/docs/build/meta.json
similarity index 52%
rename from content/docs/develop/meta.json
rename to content/docs/build/meta.json
index 899ac37..6e67398 100644
--- a/content/docs/develop/meta.json
+++ b/content/docs/build/meta.json
@@ -1,11 +1,12 @@
{
- "title": "Development",
+ "title": "Build on Solrouter",
"icon": "Code",
"pages": [
- "authentication",
+ "quickstart",
"privacy-sdk",
- "agent-tools-sdk",
"mcp-server",
- "private-swaps"
+ "agent-privacy-api",
+ "agent-tools-sdk",
+ "api-key"
]
}
diff --git a/content/docs/build/privacy-sdk.mdx b/content/docs/build/privacy-sdk.mdx
new file mode 100644
index 0000000..b0d5f3e
--- /dev/null
+++ b/content/docs/build/privacy-sdk.mdx
@@ -0,0 +1,153 @@
+---
+title: "Privacy SDK"
+icon: Code
+description: "Add encrypted AI calls to any app. Install @solrouter/sdk, pass your API key, and call client.chat(). The SDK encrypts the prompt on your machine."
+status: live
+checked: "2026-08-26"
+statusNote: "The SDK on npm (1.1.0) types gpt-oss-20b only. Other catalog ids pass through with a type cast. The model table below shows the status of each id."
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
+import { EncryptionFlow } from '@/components/diagrams/encryption-flow';
+
+Most AI APIs read your prompts in the clear. The Solrouter Privacy SDK encrypts your prompt before it leaves your machine, so the Solrouter backend cannot read it. The SDK handles the cryptography for you.
+
+Here is what happens when you call `client.chat()`. The SDK fetches the enclave's X25519 public key from `GET /tee/public-key`. It does not fetch or verify the attestation quote. That check is a manual step. See the [attestation guide](/docs/how-it-works/attestation). The SDK then encrypts your prompt on your machine with Arcium's RescueCipher. It sends the encrypted blob through the Solrouter backend, which forwards it without decrypting it. The TEE (Trusted Execution Environment, a CPU-isolated confidential VM) decrypts the prompt and calls the model on a Nosana GPU node. The node runs the model outside the enclave, so it sees the prompt and the reply in plaintext during inference. The reply comes back encrypted, and the SDK decrypts it with your session key.
+
+## Installation
+
+Install the SDK from your package manager of choice.
+
+
+
+ ```bash
+ npm install @solrouter/sdk
+ ```
+
+
+ ```bash
+ yarn add @solrouter/sdk
+ ```
+
+
+ ```bash
+ pnpm add @solrouter/sdk
+ ```
+
+
+
+## Basic usage
+
+This section walks through the calls you will make most often, starting with the default encrypted chat.
+
+### Encrypted chat (default)
+
+Every call is encrypted unless you opt out. Create a `SolRouter` client with your API key and the production `baseUrl`, then start chatting.
+
+```typescript
+import { SolRouter } from '@solrouter/sdk';
+
+const client = new SolRouter({
+ apiKey: 'sk_solrouter_...',
+ baseUrl: 'https://api.solrouter.com',
+});
+
+// Encrypted on your machine. The Solrouter backend never sees plaintext.
+const response = await client.chat('What are the risks of this DeFi protocol?');
+console.log(response.message);
+```
+
+
+ Set `baseUrl` in every client. Without it, SDK 1.1.0 defaults to a Render host, not `api.solrouter.com`.
+
+
+### Choosing a model
+
+Solrouter runs self-hosted open-weight models on Nosana GPU nodes. The backend catalog has three ids. The SDK type allows two strings. At runtime any other string passes through unchanged.
+
+| SDK string | Backend id | Status | Note |
+| ------------- | --------------- | -------- | ---------------------------------------------------------------- |
+| `gpt-oss-20b` | `gpt-oss:20b` | Live | Default. Use this with SDK 1.1.0. |
+| `qwen3-8b` | `qwen3:8b` | Archived | Alias of a retired node. Do not use. |
+| none yet | `qwen3.8:27b` | Live | Reachable with a type cast: `model: 'nosana:qwen3.8:27b' as any`. A typed alias needs a new SDK release. |
+| none yet | `gemma4:31b` | Soon | Encrypted path not confirmed end to end. |
+
+A new SDK release with the current model map is Soon.
+
+```typescript
+const response = await client.chat('Summarize the latest Solana validator outage', {
+ model: 'gpt-oss-20b', // the only typed live model string in SDK 1.1.0
+});
+```
+
+After an idle period, a node can answer with a retryable "warming up" error. Wait a moment and send the request again.
+
+### Opt out of encryption (plaintext)
+
+You can turn off client-side encryption for one call. The prompt then goes to the Solrouter backend in plaintext. The backend reads it and routes it to the same self-hosted Nosana models. No proprietary model is reachable this way.
+
+```typescript
+const response = await client.chat('Hello', { encrypted: false });
+```
+
+
+
+In words, with `encrypted: true` (the default):
+
+- Your device encrypts the prompt with RescueCipher and an X25519 shared secret.
+- The Solrouter backend forwards the ciphertext. It cannot read it.
+- The TEE decrypts the prompt and calls the model at the configured Nosana endpoint URL. The node sees the prompt in plaintext.
+- The reply comes back encrypted to your session key.
+
+In words, with `encrypted: false`:
+
+- Your device sends the prompt as plaintext.
+- The Solrouter backend reads the prompt and routes it to the same Nosana model.
+- The TEE is not used. No on-chain receipt is created.
+- The reply comes back in plaintext.
+
+### Guided reasoning (BRAID, agent path)
+
+For questions that need structured analysis, route through the agent endpoint. Setting `reasoning: 'braid'` runs your request through BRAID guided reasoning. BRAID walks a fixed Guided Reasoning Diagram (GRD) of tool steps, then makes one synthesis call to the model. Older material calls this SERV.
+
+This path is plaintext. The SDK sends the prompt to `POST /agent` without encryption and the response reports `encrypted: false`.
+
+```typescript
+const response = await client.chat('Compare Marginfi vs Kamino lending on Solana', {
+ reasoning: 'braid', // plaintext path through the agent endpoint
+});
+```
+
+### Check balance
+
+You pay per call from a prepaid balance. Check what is left at any time.
+
+```typescript
+const { balance, balanceFormatted } = await client.getBalance();
+```
+
+## SDK options reference
+
+Each of these options goes in the object you pass as the second argument to `client.chat()`.
+
+On the encrypted path, this leaves your machine: the ciphertext bundle (`ciphertext`, `nonce`, `publicKey`, `version`), plus in plaintext your API key, the model id, `chatId`, and any `systemPrompt`, `useRAG`, `ragCollection`, or `useLiveSearch` you set. The backend forwards only the bundle and the model id to the CVM.
+
+| Option | Type | Default | Description |
+| --------------- | ------- | ------------- | ------------------------------------------------------------------------------------ |
+| `model` | string | `gpt-oss-20b` | Model string. Use `gpt-oss-20b` with SDK 1.1.0. `qwen3-8b` maps to a retired node. Other catalog ids pass through with a type cast. |
+| `encrypted` | boolean | `true` | Turn client-side encryption on or off for this call |
+| `reasoning` | string | none | Set to `'braid'` for guided reasoning. This path is plaintext. |
+| `chatId` | string | none | Sent in plaintext to the backend. Not forwarded to the CVM. |
+| `systemPrompt` | string | none | Sent in plaintext to the backend. Dropped before the CVM, so it never reaches the model. |
+| `useRAG` | boolean | none | Sent in plaintext to the backend and ignored on the encrypted path. |
+| `ragCollection` | string | none | Sent in plaintext to the backend and ignored on the encrypted path. |
+| `useLiveSearch` | boolean | none | Sent in plaintext to the backend and ignored on the encrypted path. |
+
+## No KYC required
+
+Privacy starts at sign-up. You do not need an email address, a credit card, or any personal information to use the SDK. Connect your Solana wallet at [solrouter.com/sdk](https://solrouter.com/sdk), generate an API key, and top up your balance in USDC or `$ROUTER`. Pricing is metered per call from your prepaid balance.
+
+
+ Solrouter runs only self-hosted, open-weight models on the Nosana decentralized GPU network. The catalog ids are `gpt-oss:20b` (Live), `qwen3.8:27b` (Live), and `gemma4:31b` (Soon). There are no third-party model APIs: no OpenAI, Anthropic, or Google. Your prompts never go to an external model provider. The Nosana node that runs the model does see the prompt in plaintext during inference. Solrouter does not control that hardware.
+
diff --git a/content/docs/build/quickstart.mdx b/content/docs/build/quickstart.mdx
new file mode 100644
index 0000000..1e02f58
--- /dev/null
+++ b/content/docs/build/quickstart.mdx
@@ -0,0 +1,125 @@
+---
+title: "Quickstart"
+icon: Rocket
+description: "Get an API key with your Solana wallet, install @solrouter/sdk, and send your first encrypted request in a few lines of TypeScript."
+status: live
+checked: "2026-08-26"
+---
+
+import { Cards, Card } from 'fumadocs-ui/components/card';
+import { Callout } from 'fumadocs-ui/components/callout';
+import { Step, Steps } from 'fumadocs-ui/components/steps';
+import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
+import { Lock, KeyRound, Code } from 'lucide-react';
+
+Most AI APIs can read every prompt you send them. Solrouter does not: your message is encrypted on your machine before it leaves, and the backend relays it without seeing the plaintext. The next five steps set that up end to end. You sign in with a Solana wallet, install the SDK, and send your first encrypted request. No email and no credit card: you need a wallet and a few lines of TypeScript.
+
+
+
+ ### Get an API key
+
+ Your key is how Solrouter authenticates you and bills your usage. It is tied to your wallet, not your identity.
+
+ Go to [solrouter.com/sdk](https://solrouter.com/sdk), connect your Solana wallet, and generate an API key. Top up your prepaid balance in USDC or \$ROUTER to start making calls.
+
+
+ No email, no credit card, and no KYC required. Your API key is tied to your wallet.
+
+
+
+
+ ### Install the SDK
+
+ The SDK handles encryption, routing, and decryption for you, so you write normal TypeScript and get privacy by default.
+
+ Add `@solrouter/sdk` to your project using your preferred package manager.
+
+
+
+ ```bash
+ npm install @solrouter/sdk
+ ```
+
+
+ ```bash
+ yarn add @solrouter/sdk
+ ```
+
+
+ ```bash
+ pnpm add @solrouter/sdk
+ ```
+
+
+
+
+
+ ### Initialize the client
+
+ One call gets you a configured client. Pass your API key and the API base URL.
+
+ The SDK fetches the enclave's published public key from `GET /tee/public-key` before your first encrypted request. That key is the encryption target for your prompts. The SDK does not fetch or verify the attestation quote. To check the enclave yourself, see [Attestation](/docs/how-it-works/attestation).
+
+ ```typescript
+ import { SolRouter } from '@solrouter/sdk';
+
+ const client = new SolRouter({
+ apiKey: 'sk_solrouter_...',
+ baseUrl: 'https://api.solrouter.com',
+ });
+ ```
+
+
+ Set `baseUrl` explicitly. The SDK default points at a Render host, not at `api.solrouter.com`.
+
+
+
+
+ ### Send your first encrypted chat
+
+ Here the privacy guarantee pays off. Your prompt travels encrypted through the Solrouter backend. Only the TEE (Trusted Execution Environment: hardware that isolates code and data from the machine's operator) can decrypt it. The enclave then sends the plaintext to an open-weight model on a Nosana GPU node.
+
+ Call `client.chat()` to send a message. The SDK encrypts it client-side with Arcium's RescueCipher. It sends the encrypted blob through the Solrouter backend, which cannot read it. Then it decrypts the response for you.
+
+ With the current SDK, use the default model `gpt-oss-20b`. Other catalog ids pass through with a type cast; see [Models](/docs/how-it-works/models).
+
+ ```typescript
+ // Encrypted end to end: the Solrouter backend never sees plaintext
+ const response = await client.chat('What are the risks of this DeFi protocol?');
+ console.log(response.message);
+ ```
+
+ If the GPU node was idle, the first reply can say "Nosana GPU node is warming up". Wait a moment and send the request again.
+
+
+
+ ### Check your balance
+
+ Solrouter bills against prepaid funds, so you can check your remaining balance at any time. For example, check it before a batch of calls, or show it in your own UI.
+
+ Query your prepaid balance:
+
+ ```typescript
+ const { balance, balanceFormatted } = await client.getBalance();
+ console.log(`Balance: ${balanceFormatted}`);
+ ```
+
+
+
+## Next steps
+
+You have sent an encrypted request and checked your balance. That is the core loop. Where you go next depends on what you build: the full SDK surface, keyless payments, or direct HTTP access.
+
+
+ } href="/docs/build/privacy-sdk">
+ Full `@solrouter/sdk` documentation: model selection, plaintext mode (`encrypted: false`), BRAID reasoning (`reasoning: 'braid'`), and more.
+
+
+ } href="/docs/build/api-key">
+ Learn about API key auth, x402 keyless payments, and keeping your credentials safe.
+
+
+ } href="/docs/api-reference/overview">
+ Browse the full REST API, including the agent endpoint and x402 paywall spec.
+
+
diff --git a/content/docs/chat-app.mdx b/content/docs/chat-app.mdx
deleted file mode 100644
index cc70b80..0000000
--- a/content/docs/chat-app.mdx
+++ /dev/null
@@ -1,76 +0,0 @@
----
-title: "Chat App"
-icon: MessageSquare
-description: "Solrouter Chat at solrouter.com/chat gives you encrypted AI chat with file attachments, image generation, and a RAG knowledge base — no email required."
----
-
-import { Cards, Card } from 'fumadocs-ui/components/card';
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Step, Steps } from 'fumadocs-ui/components/steps';
-import { Lock, Paperclip, Image as ImageIcon, Database } from 'lucide-react';
-
-Most AI chat tools want your email, store your conversations in plaintext, and lock you into a single model. Solrouter Chat at [solrouter.com/chat](https://solrouter.com/chat) takes the opposite stance: every conversation is end-to-end encrypted by default, and you never create an account.
-
-You connect a Solana wallet, top up a prepaid balance, and switch freely between models. Along the way you get file attachments, image and video generation, and a RAG knowledge base — all private, all in one interface.
-
-## Features
-
-Here is what you get out of the box, and why each one matters for keeping your data yours.
-
-
- }>
- Your conversations stay private even from us. Each message is encrypted end-to-end and stored only in encrypted form, so neither Solrouter nor anyone else can read your history.
-
-
- }>
- Send documents along with your question. The file contents are encrypted together with your prompt before they ever leave your browser.
-
-
- }>
- Create visuals next to your text responses in the same window — no separate tool, no extra account.
-
-
- }>
- RAG (Retrieval-Augmented Generation — answering from your own documents instead of only the model's training data) lets you upload files and query them in plain language. Your documents stay encrypted the whole time.
-
-
-
-## Getting started
-
-Four steps take you from a blank browser tab to your first private message.
-
-
-
- ### Open the chat app
-
- Go to [solrouter.com/chat](https://solrouter.com/chat) in your browser.
-
-
-
- ### Connect your Solana wallet
-
- Click **Connect Wallet** and approve the request in your wallet. Your wallet is your identity here — no email address or personal information is required.
-
-
-
- ### Top up your balance
-
- Add credits in **USDC** or **`$ROUTER`**. You pay per call from this prepaid balance, so you only spend on what you use.
-
-
-
- ### Select a model and start chatting
-
- Pick a model from the selector and send your first message. Every request is encrypted by default — you do not have to turn anything on.
-
-
-
-## Supported models
-
-Solrouter routes to many models, and which ones support full privacy depends on where they run.
-
-For the full list of available models and their identifiers, see the [Supported Models](/docs/concepts/supported-models) page. Privacy mode is available for all self-hosted, open-weight models running on Solrouter's infrastructure.
-
-
- All chat history is encrypted — Solrouter cannot read your conversations. Your prompts and responses only exist in plaintext on your device and briefly inside the Intel TDX enclave during inference.
-
diff --git a/content/docs/concepts/agent-framework.mdx b/content/docs/concepts/agent-framework.mdx
deleted file mode 100644
index 945a8d3..0000000
--- a/content/docs/concepts/agent-framework.mdx
+++ /dev/null
@@ -1,83 +0,0 @@
----
-title: "Agent Framework"
-icon: LayoutDashboard
-description: "Solrouter's agent framework combines SERV guided reasoning, skill graphs, and built-in Solana tools for deterministic, cost-efficient AI agent execution."
----
-
-import { Cards, Card } from 'fumadocs-ui/components/card';
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Workflow, Share2, Lock } from 'lucide-react';
-
-A standard agent asks the LLM what to do at every step, which burns tokens, adds latency, and makes behavior hard to predict. Solrouter's agent framework removes that uncertainty: each request runs through SERV (Structured Execution via Reasoning Virtualization), which replaces freeform LLM decision-making with a deterministic execution graph.
-
-A skill-graph layer rides alongside SERV, injecting structured domain knowledge — DeFi, on-chain data, market analysis, and more — straight into the synthesis context, but only when your query actually needs it. You get an agent that reasons more reliably, spends far fewer tokens, and responds faster than a typical agent loop.
-
-## Core components
-
-The framework rests on three pieces. Start here to learn how each one works.
-
-
- } href="/docs/concepts/serv-reasoning">
- Deterministic execution graphs that replace freeform LLM decisions, cutting token cost by 79.7% and latency by 35%.
-
-
- } href="/docs/concepts/skill-graphs">
- Domain knowledge injection across 14 nodes — DeFi, on-chain signals, privacy tech, and more — activated only when needed.
-
-
- } href="/docs/develop/private-swaps">
- Agent-first surface for private on-chain swaps and x402-paywalled encrypted inference on Solana.
-
-
-
-## Built-in tools
-
-These are the tools every agent can reach without any setup. SERV picks which ones to call — and in what order — from the pre-defined execution graph for your query type, rather than asking the LLM at runtime.
-
-| Tool | Description |
-| ----------------- | ------------------------------------------------------------------------------- |
-| `web_search` | Search the web via Brave Search API for real-time information |
-| `scrape_url` | Extract and clean content from any URL |
-| `crawl_url` | Crawl entire websites via Cloudflare Browser Rendering (handles JS-heavy sites) |
-| `solana_balance` | Check SOL and SPL token balances for any wallet |
-| `token_price` | Real-time price, volume, liquidity, market cap via DexScreener + Jupiter |
-| `swap_quote` | DEX swap quotes from Jupiter aggregator |
-| `trending_tokens` | Trending / boosted tokens from DexScreener with price data |
-| `deepwiki` | AI-powered GitHub repository research via DeepWiki |
-
-## Quick example
-
-Here's the smallest request that exercises the whole pipeline. Send a prompt to the agent endpoint with your API key, and set `useTools: true` to turn on SERV-guided tool execution.
-
-```bash
-curl -X POST "https://api.solrouter.com/agent" \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "prompt": "Compare Marginfi vs Kamino lending on Solana",
- "model": "gpt-oss:20b",
- "useTools": true
- }'
-```
-
-The response gives you the synthesized reply plus a record of how the agent got there: every tool call it made, how many reasoning iterations it ran, and a skill-graph summary listing which knowledge nodes it traversed.
-
-```json
-{
- "success": true,
- "reply": "## Marginfi vs Kamino Lending Comparison\n\n...",
- "toolCalls": [
- { "tool": "web_search", "args": { "query": "Marginfi vs Kamino lending Solana" } },
- { "tool": "token_price", "args": { "token": "MNDE" } }
- ],
- "iterations": 4,
- "skillGraph": {
- "nodesTraversed": ["defi-analysis", "liquidity-risk", "comparative-analysis"],
- "relevanceScore": 0.72
- }
-}
-```
-
-
- SERV is the default reasoning mode for every agent request with `useTools: true`. A standard agent loop asks the LLM which tool to call at each step; SERV instead walks a pre-defined execution graph and calls the LLM only once at the end, to synthesize the answer. That single difference is why token cost and latency drop so sharply — and output quality holds.
-
diff --git a/content/docs/concepts/attestation.mdx b/content/docs/concepts/attestation.mdx
deleted file mode 100644
index 6ac8933..0000000
--- a/content/docs/concepts/attestation.mdx
+++ /dev/null
@@ -1,134 +0,0 @@
----
-title: "Attestation"
-icon: BadgeCheck
-description: "Every Solrouter TEE response is backed by an Intel-signed TDX quote. Fetch the attestation and verify the enclave code yourself — on-chain or off-chain."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Step, Steps } from 'fumadocs-ui/components/steps';
-import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
-
-When you send a prompt to a private inference service, how do you know it actually ran where the service claims — and on the code the service published, not a tampered copy that quietly logs your data? Solrouter answers that with attestation: hardware-signed proof you can check yourself.
-
-Every response processed inside the Solrouter TEE (Trusted Execution Environment — hardware that isolates code and data even from the machine's owner) is backed by a real Intel-signed TDX quote. That quote cryptographically binds the enclave's public key to the exact code measurement running inside the Confidential VM. You never have to take Solrouter's word for it: fetch the quote, verify Intel's signature chain, inspect the event log measurements, and confirm on-chain that your specific session ran inside an attested enclave. Trust is optional; verification is always available.
-
-## Live attestation endpoints
-
-These two endpoints hand you the raw material for verification. Query them any time to retrieve the current attestation data.
-
-### Get the TEE public key
-
-```bash
-GET https://api.solrouter.com/tee/public-key
-```
-
-This returns the X25519 public key currently active inside the Confidential VM — the key your SDK uses to encrypt prompts client-side. The enclave generates it at boot, so only the enclave holds the matching private key. Nobody on the host, including Solrouter, can decrypt traffic sealed to it.
-
-### Get the TDX attestation quote
-
-```bash
-GET https://api.solrouter.com/tee/attestation
-```
-
-This returns the Intel TDX attestation quote — the hardware-signed proof that ties everything together. Its `report_data` field contains `sha256(pubkey)`, which binds the public key you fetched above to the exact code measurement inside the CVM. Verify the quote and you confirm three things at once:
-
-1. The host CPU is a genuine Intel TDX-capable processor.
-2. The public key was generated inside that specific enclave instance.
-3. The enclave is running the code Solrouter publishes — not a modified version.
-
-## What you can verify
-
-Attestation only matters if you can check the claims independently. Here is exactly what the quote lets you prove on your own, with no input from Solrouter:
-
-* **Intel root chain** — the TDX quote is signed by an Intel-issued key. Verifying the signature chain confirms the hardware is a genuine TDX CPU, not a simulated or spoofed environment.
-* **Code measurements** — the event log inside the quote includes verifiable measurements of every component in the running stack:
- * `compose-hash` — the container composition that defines the enclave workload
- * `app-id` — the specific application image
- * `os-image-hash` — the guest OS image loaded into the CVM
- * `mr-kms` — the KMS measurement used for key management
-* **Public key binding** — because `report_data = sha256(pubkey)`, you can confirm that the key used to encrypt your prompt belongs to this exact enclave instance, not an interceptor sitting in the middle.
-
-
- Advanced users can verify the full Intel TDX quote chain independently using Intel's DCAP (Data Center Attestation Primitives) libraries or a third-party TEE verification service. The quote Solrouter returns is a standard TDX quote — no proprietary format.
-
-
-## On-chain attestation anchor
-
-Off-chain verification proves the enclave is genuine, but it lives in a response you have to trust Solrouter to keep. For a record nobody can quietly edit later, Solrouter anchors attestation data to Solana mainnet.
-
-The Solrouter encryption-attestation program is deployed at:
-
-```
-ATMRatMtsKX4bHax7U4FRdhbE4mjU4NKpDZGqZqAhBKb
-```
-
-Each privacy-mode session can publish a **PDA (Program Derived Address — an account whose address is deterministically derived from the program)** that links that specific request to the attested TEE. Once it settles on-chain, there is an immutable, publicly verifiable record that your interaction ran inside a verified enclave — not just a log entry in Solrouter's database that could change.
-
-To fetch the on-chain attestation PDA for any session, use the `umbra_attestation` tool in the Agent Tools SDK or MCP server:
-
-
-
- ```typescript
- import { SolrouterAgentClient, callTool } from '@solrouter/agent-tools';
-
- const client = new SolrouterAgentClient({ apiKey: 'sk_solrouter_...' });
-
- // Fetch the on-chain attestation for a completed session.
- // callTool is a standalone function — pass the client as the first arg.
- // (Equivalent direct method: client.attestation('your-session-id'))
- const attestation = await callTool(client, 'umbra_attestation', {
- sessionId: 'your-session-id',
- });
-
- console.log(attestation);
- ```
-
-
- ```bash
- # In your MCP-connected client, call:
- umbra_attestation({ sessionId: "your-session-id" })
- ```
-
-
-
-## Verification flow
-
-Here is the end-to-end check, from fetching the key to confirming the on-chain anchor. Each step builds on the last, and the final one is optional.
-
-
-
-### Fetch the public key
-
-Call `GET https://api.solrouter.com/tee/public-key` and store the returned X25519 public key.
-
-
-
-### Fetch the attestation quote
-
-Call `GET https://api.solrouter.com/tee/attestation` to retrieve the Intel TDX quote.
-
-
-
-### Verify the quote signature
-
-Use Intel DCAP or a compatible TEE verification library to validate the quote's signature chain back to Intel's root certificate. This proves the hardware is real.
-
-
-
-### Check report_data
-
-Confirm that `report_data` in the quote equals `sha256(pubkey)` from Step 1. This binds the public key to the verified enclave, so you know you encrypted to the right key.
-
-
-
-### Inspect code measurements
-
-Compare the `compose-hash`, `app-id`, `os-image-hash`, and `mr-kms` values against what Solrouter publishes in its open-source repository to confirm you are running the expected code.
-
-
-
-### Check the on-chain anchor (optional)
-
-Look up the session PDA on Solana mainnet at `ATMRatMtsKX4bHax7U4FRdhbE4mjU4NKpDZGqZqAhBKb` to confirm the on-chain settlement record.
-
-
diff --git a/content/docs/concepts/encryption-proof.mdx b/content/docs/concepts/encryption-proof.mdx
deleted file mode 100644
index 948af35..0000000
--- a/content/docs/concepts/encryption-proof.mdx
+++ /dev/null
@@ -1,119 +0,0 @@
----
-title: "Encryption Proof"
-icon: Stamp
-description: "Every private inference writes an on-chain receipt signed inside the Intel TDX enclave. Paste the lock-icon link from any chat message — or an address, hash, or tx — and verify it yourself."
----
-
-import { EncryptionProofVerifier } from '@/components/verify/encryption-proof-verifier';
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Step, Steps } from 'fumadocs-ui/components/steps';
-
-[Attestation](/docs/concepts/attestation) proves the enclave is genuine. The **encryption proof** ties *your specific request* to that enclave: a TDX-attested enclave signs your exact ciphertext hash with a key that exists only inside the enclave, and writes the receipt to Solana. The backend relays it but can't forge it.
-
-Each receipt is a **Light Protocol compressed account** — about **0.000005 SOL each, ~400× cheaper than a normal Solana PDA**. That cost gap is the whole reason a proof *per message* is viable: a standard PDA for every inference would be economically absurd at scale; compression makes it routine.
-
-## Verify a proof
-
-In chat, every private-mode reply has a **🔒 next to it — click it, copy the link, and paste it here.** You can also paste a Light attestation address, the commit-transaction signature, or the 64-character encrypted-prompt hash. The widget reads the on-chain record and verifies the enclave's ed25519 signature **in your browser** — no trust in Solrouter required.
-
-
-
-## Verifying from an agent or the SDK
-
-Chat hands you a clickable lock link. The **agent API and SDK** hand you the proof in the response payload instead — every private inference returns an `onchainAttestation` object:
-
-```json
-{
- "address": "12Qenx1LK3ddTX5F3Apm6HYFFjswL3acSYNYXqUHTAVn", // Light compressed account
- "encryptedPromptHash": "5b17ccd7…", // sha256(ciphertext)
- "signature": "4RFJVwSC…", // the commit transaction
- "explorerUrl": "https://solscan.io/tx/4RFJVwSC…"
-}
-```
-
-Verify it three equivalent ways — paste any of these into the widget above, or hit the public, CORS-open endpoints directly:
-
-```bash
-# by the commit-transaction signature (what `signature` / the 🔒 link points to)
-curl https://api.solrouter.com/attestation/by-tx/
-
-# by the attestation address
-curl https://api.solrouter.com/attestation/
-
-# by the encrypted-prompt hash
-curl https://api.solrouter.com/attestation/by-hash/
-```
-
-Each returns the full record with `version: "v2"` and every proof field below — ready to check, in your own code, against the enclave's signature.
-
-
- The lock link is a transaction link (a compressed account can't be browsed on
- Solscan). The `by-tx` endpoint reads the commit transaction, pulls the
- encrypted-prompt hash out of its instruction data, and re-derives the
- attestation address — so the link you already have is enough.
-
-
-## What the record stores, and what gets signed
-
-A v2 attestation lives under the Solrouter program `ATMRatMtsKX4bHax7U4FRdhbE4mjU4NKpDZGqZqAhBKb`. Its address is **deterministic** — `deriveAddressV2(["attestation_v2", sha256(ciphertext)], …)` — which is why a bare hash is enough to find it. Alongside the basics (`model`, `provider`, `timestamp`, `backend_saw_plaintext`, `tee_processed`) it stores the proof:
-
-| Field | Meaning |
-| --- | --- |
-| `client_pubkey` | Your ephemeral X25519 key from the request |
-| `tee_pubkey` | The enclave's X25519 sealing key your ciphertext was sealed to |
-| `nonce` | The RescueCipher nonce |
-| `enclave_pubkey` | The enclave's ed25519 signing key — **bound inside the TDX quote** |
-| `enclave_sig_r` / `enclave_sig_s` | The two halves of the ed25519 signature |
-| `tdx_quote_hash` | `sha256` of the TDX quote that attests `enclave_pubkey` |
-
-Inside the Confidential VM, the enclave signs this exact byte tuple:
-
-```
-"SOLR-ATTEST-v2"
- ‖ sha256(ciphertext) // 32 your encrypted prompt
- ‖ tee_pubkey // 32 the sealing key
- ‖ nonce // 16
- ‖ client_pubkey // 32 your request key
- ‖ len(model) ‖ model
- ‖ len(provider) ‖ provider
-```
-
-## Verify the signature yourself, by hand
-
-
-
-### Read the record
-
-Use any of the `curl` calls above. You get back `version: "v2"` plus every field — `encryptedPromptHash` (hex); `teePubkey`, `nonce`, `clientPubkey`, `enclavePubkey`, `enclaveSigR`, `enclaveSigS` (base64).
-
-
-
-### Rebuild the signed message
-
-Concatenate the tuple above from the record bytes (`encryptedPromptHash` decoded from hex; the keys/nonce decoded from base64).
-
-
-
-### Check the signature
-
-Reassemble the 64-byte signature as `enclaveSigR ‖ enclaveSigS` and verify it over your message against `enclavePubkey` with any Ed25519 library. If a single byte was tampered — different ciphertext, swapped key, forged signer — it fails.
-
-
-
-### (Optional) Anchor the signing key in hardware
-
-Confirm `enclave_pubkey` is the key bound into the TDX quote: fetch `GET /tee/attestation` and check the quote's `report_data` equals `sha256(tee_pubkey ‖ enclave_pubkey)`. That proves the signer is the attested enclave, not an impostor.
-
-
-
-## Why the backend can't forge it
-
-The ed25519 signing key is generated **inside** the enclave at boot and never leaves it. Its public half is committed into the TDX quote's `report_data`, so anyone can confirm the signer is the genuine, attested enclave. The backend relays the proof onto Solana but never holds the private key — it can publish a real receipt, and it has nothing to forge a fake one with.
-
-
- A passing check proves an attested TDX enclave received and signed *your exact
- ciphertext*, and that the record is committed on-chain. For the deepest level —
- verifying Intel's full DCAP signature chain on the raw TDX quote — fetch the
- live quote from `GET /tee/attestation` and run it through Intel's DCAP
- libraries. The on-chain record stores the quote's hash, not the full quote.
-
diff --git a/content/docs/concepts/encryption.mdx b/content/docs/concepts/encryption.mdx
deleted file mode 100644
index f291c74..0000000
--- a/content/docs/concepts/encryption.mdx
+++ /dev/null
@@ -1,125 +0,0 @@
----
-title: "Encryption"
-icon: Lock
-description: "Solrouter uses Arcium RescueCipher with X25519 key exchange for client-side encryption. Plaintext exists only inside an attested Intel TDX enclave."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
-
-When you send a prompt to an AI provider, you normally trust that provider to read it, store it, and not misuse it. Solrouter removes that trust requirement. Your prompt is encrypted on your own device before it leaves, and Solrouter's backend never holds the key to read it.
-
-Solrouter encrypts your prompts and responses with Arcium's `RescueCipher` cipher and `X25519` key exchange (a fast, modern way for two parties to agree on a shared secret without ever transmitting it). The ciphertext travels through Solrouter's backend untouched, and is decrypted only inside a hardware-isolated Intel TDX Confidential VM — a TEE (Trusted Execution Environment: hardware that isolates code and data even from the machine's owner). Solrouter's backend is a blind relay: it routes encrypted blobs it cannot read, and the private key that could decrypt them never leaves the enclave.
-
-## Encryption components
-
-Here are the three building blocks that make the guarantee work, and what each one does.
-
-### Client-side encryption
-
-The first line of defense is simple: encrypt before you transmit. Your prompt is encrypted locally — in the browser or in your server process — before it is sent anywhere.
-
-* **`RescueCipher`** — Arcium's field-element symmetric cipher. Arcium chose it for compatibility with MPC, FHE, and ZK computation, so the same encrypted payload can be processed under any of those paradigms as Arcium's network matures.
-* **`X25519` key exchange** — your SDK session generates an ephemeral (single-use, per-session) X25519 keypair. The shared secret is derived from your ephemeral private key and the TEE's attested public key.
-* **TEE-generated keypair** — the TEE's own X25519 keypair is generated inside the Confidential VM at boot time. The private key never leaves the enclave — not even to Solrouter's own infrastructure.
-
-### Inference isolation
-
-Your data has to be decrypted somewhere to run the model. The question is *where*, and who can see it. With Solrouter, decryption and inference happen exclusively inside an attested enclave.
-
-* **Intel TDX Confidential VM** — a hardware-enforced TEE. Memory is encrypted by the CPU and inaccessible to the host OS, hypervisor, and any Solrouter process running outside the enclave.
-* **Plaintext exists only inside attested enclave memory** — the moment the model finishes generating a response, it is re-encrypted with your session's ephemeral key before it exits the enclave.
-* **No host access** — no Solrouter employee, server process, or privileged operator can read your prompt or response. This is a hardware guarantee, not a policy promise.
-
-### Transport
-
-Encryption only helps if there is no gap where plaintext leaks in transit. There is none.
-
-* All traffic between your client and the enclave is encrypted end-to-end. There is no TLS termination point where plaintext is visible to an intermediary.
-* The Solrouter backend is a **blind relay** — it forwards encrypted blobs without being able to decrypt them. It never has the keys.
-
-```
-You (Browser / SDK)
- │
- ├── RescueCipher encrypts prompt client-side
- │ with TEE's attested X25519 public key
- │
- ▼
-Solrouter Backend
- │
- ├── Cannot decrypt. Routes encrypted blob blindly.
- │
- ▼
-Intel TDX Enclave
- │
- ├── Hardware-isolated decryption inside the enclave
- ├── Runs the model with plaintext (in-enclave only)
- ├── Encrypts response with your ephemeral session key
- │
- ▼
-Solrouter Backend
- │
- ├── Still cannot see anything
- │
- ▼
-You
- │
- └── Decrypt with your ephemeral private key
-```
-
-## Why RescueCipher?
-
-You might wonder why Solrouter does not just use a familiar cipher like AES. The answer is about where your data can go next.
-
-Most symmetric ciphers (AES-GCM, ChaCha20) are designed for classical computation. They are efficient on CPUs and GPUs but are not naturally compatible with the algebraic structures that MPC, FHE, and ZK proofs operate over.
-
-RescueCipher is a **field-element cipher** — it operates natively over the same finite-field arithmetic that MPC, FHE, and ZK systems use. That gives you three things:
-
-* The same encrypted payload you send today can, in principle, be processed directly under MPC or FHE computation without re-encryption.
-* As Arcium's MXE (Multiparty eXecution Environment) network ships support for more cryptographic compute primitives, Solrouter's encryption layer does not need to change.
-* You get a smooth upgrade path: stronger cryptographic compute guarantees over time, zero migration work on your side.
-
-This is why Arcium chose RescueCipher as the cipher for its MXE substrate — and why Solrouter uses it today, even before full MPC/FHE inference is live.
-
-## What encryption does NOT cover (yet)
-
-Privacy claims in this space are often inflated, so here is the honest line on what Solrouter does and does not do today.
-
-
- Solrouter is **not** running pure FHE (Fully Homomorphic Encryption) inference today — and no production system does. LLM-scale FHE inference is many orders of magnitude away from viable latency. Anyone claiming "FHE LLM inference" in production is overclaiming.
-
- What Solrouter offers today is **client-side encryption + hardware TEE isolation**, which is a real and meaningful guarantee. Arcium's MXE is a hybrid of MPC + FHE + ZK primitives, and RescueCipher is designed to work with all three. As Arcium's network matures, more of the inference pipeline will move from TEE-isolated plaintext into cryptographic compute — MPC first, then FHE/ZK where they are practical. The client encryption layer stays unchanged throughout.
-
-
-To be precise about what is and is not guaranteed today:
-
-| Property | Today |
-| ------------------------------------------ | ---------------------------------- |
-| Client-side encryption before transmission | ✅ Yes — RescueCipher + X25519 |
-| Plaintext isolated from Solrouter backend | ✅ Yes — Intel TDX enclave |
-| Verifiable attestation of enclave code | ✅ Yes — Intel-signed TDX quote |
-| MPC-based inference | 🔜 Roadmap — Arcium MXE |
-| Full FHE inference | ❌ Not in production anywhere today |
-
-## Encryption options in the SDK
-
-Encryption is on by default — you do not have to do anything to get it. You can turn it off for a faster plaintext path, but you give up every privacy guarantee on this page when you do.
-
-
-
- ```typescript
- // Default — fully encrypted (recommended)
- const response = await client.chat('Your prompt', { encrypted: true });
- ```
-
-
- ```typescript
- // Plaintext path — faster, no encryption guarantees
- const response = await client.chat('Your prompt', { encrypted: false });
- ```
-
-
-
-
- When you set `encrypted: false`, your prompt and response travel in plaintext through Solrouter's infrastructure. Use the plaintext path only for non-sensitive workloads where latency is your primary concern.
-
diff --git a/content/docs/concepts/how-it-works.mdx b/content/docs/concepts/how-it-works.mdx
deleted file mode 100644
index 2740b1c..0000000
--- a/content/docs/concepts/how-it-works.mdx
+++ /dev/null
@@ -1,96 +0,0 @@
----
-title: "How It Works"
-icon: Workflow
-description: Solrouter uses Arcium RescueCipher with X25519 key exchange and Intel TDX Trusted Execution Environments so plaintext never leaves the enclave.
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-import { EncryptionFlow } from '@/components/diagrams/encryption-flow';
-
-Most AI providers see every word you send. Solrouter is built so that it cannot — even though it routes your traffic.
-
-When you send a message, your prompt is encrypted on your device before it leaves your application. The Solrouter backend never sees plaintext. It forwards an opaque encrypted blob to an Intel TDX Confidential VM (a Trusted Execution Environment, or TEE — hardware that isolates code and data even from the machine's owner), where only attested enclave code can decrypt and process your request.
-
-The enclave re-encrypts the response and returns it for you to decrypt locally. Unencrypted content never exists outside the enclave boundary.
-
-## Encryption Stack
-
-This section walks through the four layers of the pipeline. Each is built so that a breach at any single layer — including Solrouter's own infrastructure — still does not expose your data.
-
-**Client-side encryption**
-
-Your prompt is encrypted before it leaves your device using Arcium's **RescueCipher**, a field-element symmetric cipher. The session key comes from an **X25519 key exchange** with the TEE's attested public key. The TEE generates its X25519 keypair inside the Confidential VM at boot and the private key never leaves the enclave, so only the enclave can derive the shared session secret. No one in the middle can.
-
-**Inference isolation**
-
-The Solrouter backend acts as a blind relay: it takes the encrypted blob and forwards it to an **Intel TDX Confidential VM**, a hardware-level Trusted Execution Environment where the host operating system and hypervisor cannot read enclave memory. Decryption, model inference, and response encryption all happen inside that isolated boundary — never on the open server.
-
-**Transport**
-
-The channel between your client and the enclave is encrypted end-to-end. The backend infrastructure handles only ciphertext, never plaintext content.
-
-**Verifiable attestation**
-
-You should not have to take our word that the right code is running. The enclave publishes an **Intel-signed TDX quote** that cryptographically binds its X25519 public key to the exact code measurement of the running image. Fetch the quote from `GET /tee/attestation` and verify for yourself that the enclave handling your request is the published, unmodified Solrouter code — not something we swapped in.
-
-## Request Flow
-
-To make the guarantees concrete, here is the complete path a privacy-mode request travels — and where, at each hop, your data stays encrypted:
-
-
-
-```text
-You (Browser / SDK)
- │
- ├── Arcium RescueCipher encrypts prompt client-side
- │ with TEE's attested X25519 public key
- │
- ▼
-Solrouter Backend
- │
- ├── Cannot decrypt. Routes encrypted blob blindly
- │
- ▼
-Intel TDX Enclave
- │
- ├── Hardware-isolated decryption inside the enclave
- ├── Runs the model on plaintext (in-enclave only)
- ├── Encrypts response with the session's ephemeral key
- │
- ▼
-Solrouter Backend
- │
- ├── Still can't see anything
- │
- ▼
-You
- │
- └── Decrypt with your ephemeral private key
-```
-
-## What Is Not (Yet) Encrypted
-
-Privacy claims are easy to inflate, so here is exactly where the guarantee ends today.
-
-
- Solrouter is **not** running pure fully homomorphic encryption (FHE) inference
- today. No production system runs LLM-scale inference under FHE in 2026 — the
- compute overhead is many orders of magnitude away from viable latency. Anyone
- claiming "FHE LLM inference" in production is overclaiming.
-
- What Solrouter provides is Arcium-encrypted transport combined with Intel TDX
- hardware isolation during compute, anchored by a real on-chain attestation
- program on Solana mainnet. That is a meaningful and verifiable privacy
- guarantee — it is simply not the same as FHE inference, and we will not claim
- otherwise.
-
-
-The honest summary: your prompt is encrypted in transit and isolated during compute inside a hardware-enforced enclave. The model runs on plaintext inside that enclave. That plaintext is inaccessible to Solrouter, the host, or anyone watching the network — but it is not processed under FHE.
-
-## Roadmap
-
-The current TEE pipeline is a starting point, not the ceiling. Here is where the privacy model is headed and why your integration won't have to change to follow it.
-
-Solrouter is built on Arcium's MXE (Multiparty eXecution Environment) substrate, which combines MPC, FHE, and ZK primitives. Choosing **RescueCipher** — a field-element cipher — was deliberate: the same encrypted payloads that flow through today's TEE pipeline can later be processed under MPC, FHE, or ZK circuits as Arcium's network matures, with no changes to the client encryption layer.
-
-As the MXE network ships in production, more of the inference pipeline moves from TEE-isolated plaintext into cryptographic compute: MPC first, then FHE and ZK primitives where they make practical sense for latency and cost. When that shift happens, your integration stays the same — the encryption layer you use today is already compatible.
diff --git a/content/docs/concepts/meta.json b/content/docs/concepts/meta.json
deleted file mode 100644
index 2e40a6c..0000000
--- a/content/docs/concepts/meta.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "title": "Core Concepts",
- "icon": "BookOpen",
- "pages": [
- "how-it-works",
- "encryption",
- "attestation",
- "encryption-proof",
- "supported-models",
- "agent-framework",
- "serv-reasoning",
- "skill-graphs"
- ]
-}
diff --git a/content/docs/concepts/serv-reasoning.mdx b/content/docs/concepts/serv-reasoning.mdx
deleted file mode 100644
index 752e9ac..0000000
--- a/content/docs/concepts/serv-reasoning.mdx
+++ /dev/null
@@ -1,102 +0,0 @@
----
-title: "SERV Reasoning"
-icon: BrainCircuit
-description: "SERV replaces freeform LLM decisions with deterministic guided reasoning diagrams, cutting token costs by 79.7% and latency by 35% with no quality loss."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Step, Steps } from 'fumadocs-ui/components/steps';
-
-A standard agent loop asks the LLM what to do at every step, which is slow, expensive, and unpredictable. SERV (Structured Execution via Reasoning Virtualization) fixes that by separating the two jobs an agent actually does: deciding *what* to gather, and writing *the answer*.
-
-Instead of asking the model what to do next, SERV walks a Guided Reasoning Diagram (GRD) — a pre-defined execution graph that controls tool selection, sequencing, and data collection on its own, with no LLM in the loop. The model is called exactly once, at the very end, to turn the collected data into a natural language response.
-
-Splitting structure from synthesis is the whole trick: it makes SERV far cheaper and faster than a standard agent loop while keeping output quality high.
-
-## Performance results
-
-Here is what that split buys you, benchmarked against a standard agent loop on identical complex research queries:
-
-| Metric | Standard | SERV | Improvement |
-| ----------- | ------------ | ----------- | ----------- |
-| Quality | 80/100 | 93/100 | +13 |
-| Token cost | 19,917/query | 4,047/query | -79.7% |
-| Latency | 24.0s | 15.7s | -35% |
-| Reliability | 100% | 100% | Parity |
-
-SERV cuts cost and latency *and* improves quality, with no loss in reliability. The quality gain is not magic: because the GRD gathers data the same structured way every time, the model synthesizes from a complete, consistent picture instead of improvising its own research path.
-
-## How SERV works
-
-This section walks through the four stages a query passes through, and why each one keeps the LLM out of the decisions it isn't good at.
-
-A standard agent loop asks the model the same question at every step: "Given what you know so far, what tool should you call next?" That burns tokens on structural choices the model has no special advantage in making, and it introduces non-determinism that can derail a complex query halfway through.
-
-SERV takes a different approach:
-
-
-
- ### Query classification
-
- The incoming prompt is classified into a query type (e.g. DeFi comparison, wallet audit, token research). Each query type maps to a pre-defined Guided Reasoning Diagram.
-
-
-
- ### GRD execution
-
- SERV walks the diagram node by node — calling tools, collecting data, and branching on results — all deterministically, without LLM involvement.
-
-
-
- ### Skill graph injection
-
- If the query type triggers relevant knowledge nodes, the skill graph injects domain context into the synthesis payload. See [Skill Graphs](/docs/concepts/skill-graphs) for details.
-
-
-
- ### LLM synthesis
-
- Only after all data is collected does SERV call the LLM — once — to transform the structured results into a coherent natural language response.
-
-
-
-The key insight: don't ask a 20B model to make structural decisions. Do those deterministically, and reserve the LLM for the one task it does best — turning raw information into useful language.
-
-## Using SERV in the SDK
-
-The fastest way to try SERV is through the SDK. Pass `reasoning: 'braid'` to the `chat()` method, and your request routes through the agent endpoint with SERV-guided reasoning enabled.
-
-```typescript
-import { SolRouter } from '@solrouter/sdk';
-
-const client = new SolRouter({
- apiKey: 'sk_solrouter_...'
-});
-
-const response = await client.chat('Compare Marginfi vs Kamino lending on Solana', {
- reasoning: 'braid', // enables SERV-guided reasoning
-});
-
-console.log(response.message);
-```
-
-## Using SERV via the API
-
-If you're not using the SDK, you can call the agent endpoint directly over HTTP. Set `useTools: true` to activate the SERV execution graph.
-
-```bash
-curl -X POST "https://api.solrouter.com/agent" \
- -H "Authorization: Bearer YOUR_API_KEY" \
- -H "Content-Type: application/json" \
- -d '{
- "prompt": "Compare Marginfi vs Kamino lending on Solana",
- "model": "gpt-oss:20b",
- "useTools": true
- }'
-```
-
-The response includes an `iterations` field showing how many GRD steps SERV executed, and a `toolCalls` array logging every tool the agent invoked and with what arguments.
-
-
- SERV shines on complex, multi-step research queries — protocol comparisons, wallet audits, market analysis, tokenomics deep-dives — where structured data gathering pays off. For simple lookups like a single token price or swap quote, a direct tool call is faster. SERV's skill graph traversal is selective and skips automatically for lightweight queries, but if you already know your query is simple, calling the relevant tool directly gives you the lowest possible latency.
-
diff --git a/content/docs/concepts/skill-graphs.mdx b/content/docs/concepts/skill-graphs.mdx
deleted file mode 100644
index ddb74c5..0000000
--- a/content/docs/concepts/skill-graphs.mdx
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: "Skill Graphs"
-icon: Network
-description: "Skill graphs inject structured domain knowledge into Solrouter agent responses for DeFi, on-chain data, and market analysis — activated only when needed."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-
-An LLM asked about a DeFi protocol has to reconstruct specialist knowledge — risk frameworks, liquidity heuristics, evaluation criteria — from whatever it happened to absorb during training. That is slow and unreliable. Skill graphs fix this by handing the model that expertise as structured input, before it ever starts answering.
-
-A skill graph is Solrouter's domain-knowledge layer. It sits between tool execution and LLM synthesis in the SERV pipeline. When your query matches the trigger conditions of one or more skill nodes, the engine walks the connected graph and injects the relevant expertise straight into the synthesis context.
-
-The payoff: the model writes from curated knowledge rather than guessing. You get more accurate, more nuanced answers on hard topics — and because the knowledge is injected only when it applies, there is no extra token overhead on queries that don't need it.
-
-## Knowledge domains
-
-This is the catalog of expertise the engine can draw on. Solrouter ships with 14 base knowledge nodes across four areas. Each node carries curated heuristics, definitions, risk frameworks, and evaluation criteria that the LLM uses during synthesis.
-
-**DeFi & Markets**
-
-* **DeFi protocol analysis** — lending, borrowing, AMM mechanics, TVL interpretation, protocol risk
-* **Liquidity risk** — slippage, depth, impermanent loss, pool concentration
-* **Tokenomics** — emission schedules, vesting, buyback models, supply dynamics
-* **Market analysis** — price action, volume interpretation, trend identification
-* **On-chain signals** — transaction patterns, fee pressure, validator behavior, network health
-* **Whale tracking** — large-wallet behavior, accumulation/distribution signals
-
-**Portfolio & Wallets**
-
-* **Wallet analysis** — address clustering, activity patterns, counterparty relationships
-* **Portfolio risk assessment** — concentration risk, correlation, drawdown analysis
-
-**Technical & Research**
-
-* **Privacy / encryption technology** — MPC, ZK proofs, TEE architecture, FHE fundamentals
-* **Research methodology** — structured inquiry, source triangulation, claim verification
-* **Source evaluation** — credibility scoring, recency weighting, conflict detection
-* **Comparative analysis** — side-by-side frameworks, trade-off matrices, scoring rubrics
-
-**Ecosystem**
-
-* **Solana ecosystem knowledge** — native programs, validator economics, fee markets, SPL standards
-* **Solana DeFi landscape** — protocol relationships, liquidity flows, ecosystem interdependencies
-
-## Selective activation
-
-Domain knowledge is only worth injecting when the query actually calls for it — so the engine decides per query whether to use the skill graph at all. It checks the incoming query against each node's trigger conditions before traversing anything.
-
-
- Simple queries — price checks, swap quotes, balance lookups — skip skill-graph traversal entirely. Activating domain knowledge for a single `token_price` call would add latency and tokens with no quality benefit. SERV is designed to match overhead to complexity: the skill graph fires when it helps, and stays silent when it doesn't.
-
-
-When traversal does happen, the engine pulls only the nodes the query needs. A DeFi protocol comparison might walk `defi-analysis`, `liquidity-risk`, and `comparative-analysis` while leaving the wallet and privacy nodes untouched.
-
-## Skill graph in API responses
-
-You don't have to guess what the engine did — every response tells you. Each agent response includes a `skillGraph` object reporting exactly which nodes were traversed and how confident the engine was in the match.
-
-```json
-{
- "skillGraph": {
- "nodesTraversed": ["defi-analysis", "liquidity-risk", "comparative-analysis"],
- "relevanceScore": 0.72
- }
-}
-```
-
-**`nodesTraversed`** — the ordered list of skill nodes the engine walked before synthesis. Read it to see which domain lenses the agent applied to your query. An empty array means the query was handled without skill-graph activation.
-
-**`relevanceScore`** — a float between 0 and 1 measuring how strongly the query matched the traversed nodes. A higher score means a tight semantic match between the query and the activated domain knowledge; a lower score means the engine traversed cautiously on a weaker signal. The `0.72` above is a solid but not perfect match — typical for a broad comparative query that spans several DeFi topics.
diff --git a/content/docs/concepts/supported-models.mdx b/content/docs/concepts/supported-models.mdx
deleted file mode 100644
index 60ab214..0000000
--- a/content/docs/concepts/supported-models.mdx
+++ /dev/null
@@ -1,56 +0,0 @@
----
-title: "Models"
-icon: Layers
-description: "Solrouter runs only self-hosted open-weight models on the Nosana GPU network — no prompts reach OpenAI, Anthropic, or any third-party provider."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-
-When you turn on privacy mode, Solrouter answers you using only self-hosted, open-weight models — never a proprietary API. That choice is deliberate: it's what lets the privacy guarantee actually hold.
-
-Every model runs on the [Nosana](https://nosana.io) decentralized GPU network. Your encrypted request travels from your device to an Intel TDX enclave (a hardware-isolated execution environment that keeps your data sealed even from the machine's operator), runs against one of the models below, and goes nowhere else. There are no integrations with proprietary model APIs in this path.
-
-## Available Models
-
-These are the open-weight models you can run in privacy mode today, with the ID you pass when selecting one.
-
-| Model | ID | License | Notes |
-| ----------- | ------------- | ------------ | ------------------------------------------------------------------ |
-| GPT-OSS 20B | `gpt-oss-20b` | Apache-2.0 | Default model. Strong general reasoning and instruction following. |
-| Qwen 3 8B | `qwen3-8b` | Open weights | Lighter-weight alternative. Faster responses for simpler tasks. |
-
-Both models are open-weight: their architecture and weights are public, so anyone can audit them. You aren't trusting a black box — you can inspect exactly what is running on your prompt.
-
-## Choosing a Model
-
-This is how you pick a model in code, and when to reach for each one.
-
-Leave the model out and Solrouter defaults to `gpt-oss-20b`. To choose explicitly, pass it as an option to `client.chat()`:
-
-```typescript
-const response = await client.chat('Your prompt here', {
- model: 'gpt-oss-20b', // gpt-oss-20b (default) | qwen3-8b
-});
-```
-
-Reach for `qwen3-8b` when speed matters more than depth — short, straightforward queries. Reach for `gpt-oss-20b` when the task needs stronger reasoning, longer context, or detailed synthesis.
-
-
- Call `list_models` via the MCP server to confirm which models are currently live and what each one costs per call.
-
-
-## Why Self-Hosted Models?
-
-Here's the reasoning behind the constraint — why Solrouter refuses to route privacy-mode traffic to any third party.
-
-End-to-end privacy only holds if your prompt never reaches a third-party API. The moment Solrouter handed your decrypted prompt to OpenAI or Anthropic, that provider would see your plaintext — and client-side encryption plus TEE isolation would have bought you nothing.
-
-Running only open-weight models on the Nosana network closes that gap. It means:
-
-* Your prompt leaves the Intel TDX enclave only as a re-encrypted response sent back to you.
-* No third-party model provider ever sees your query, your documents, or your response.
-* The inference infrastructure stays auditable — Nosana's decentralized network and open-weight models don't depend on any single company's closed systems.
-
-
- There are no third-party model APIs in the Solrouter privacy pipeline — no OpenAI, no Anthropic, no Google, no Midjourney. If you need a proprietary model, you can disable encryption with `{ encrypted: false }`, but those prompts no longer get TEE isolation or the privacy guarantees described here.
-
diff --git a/content/docs/develop/agent-tools-sdk.mdx b/content/docs/develop/agent-tools-sdk.mdx
deleted file mode 100644
index b953920..0000000
--- a/content/docs/develop/agent-tools-sdk.mdx
+++ /dev/null
@@ -1,106 +0,0 @@
----
-title: "Agent Tools SDK"
-icon: Bot
-description: "Typed tools for the Solrouter Agent Privacy API with a Vercel AI SDK adapter. Enable AI agents to execute privacy-preserving on-chain swaps on Solana."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
-
-If you want an AI agent to swap tokens on Solana without leaking who is trading what, you normally have to wire up quoting, signing, mixing, and settlement yourself. `@solrouter/agent-tools` removes that work: it gives you typed tools for the Solrouter Agent Privacy API (`/agents/v1`) so your agent can quote, execute, and settle privacy-preserving swaps and encrypted inference out of the box.
-
-It ships with a first-class Vercel AI SDK adapter, so you drop it into your agent without writing an orchestration layer. Not on the AI SDK? The raw `TOOLS` (JSON Schema definitions) and the `callTool()` function are also exported, so any function-calling framework works — you're never locked into a single AI runtime.
-
-## Installation
-
-Add the package with your usual package manager.
-
-
-
- ```bash
- npm install @solrouter/agent-tools
- ```
-
-
- ```bash
- yarn add @solrouter/agent-tools
- ```
-
-
- ```bash
- pnpm add @solrouter/agent-tools
- ```
-
-
-
-## Vercel AI SDK quickstart
-
-This is the fastest path: let an LLM decide when to swap, and let the adapter handle the plumbing. Pass `aiSdkTools(solrouter)` straight into `generateText` or `streamText` — it wires up the tool schemas, validates the model's arguments, and marshals results back for you.
-
-```typescript
-import { generateText } from "ai";
-import { SolrouterAgentClient } from "@solrouter/agent-tools";
-import { aiSdkTools } from "@solrouter/agent-tools/ai-sdk";
-
-const solrouter = new SolrouterAgentClient({
- apiKey: process.env.SOLROUTER_API_KEY,
-});
-
-const result = await generateText({
- model: yourModel, // any AI SDK model provider
- tools: aiSdkTools(solrouter),
- prompt: "Privately swap 0.01 SOL to USDC and send the USDC to AAA...XXX",
-});
-```
-
-## Direct usage (no LLM)
-
-Sometimes you don't want a model in the loop — you want to drive the privacy pipeline yourself in code. Mode B one-shot swaps do exactly that. Your agent signs the funding transaction with its own wallet, then Solrouter runs the 7-step mixer, the Jupiter swap, and the forward-to-destination pipeline.
-
-```typescript
-import { SolrouterAgentClient } from "@solrouter/agent-tools";
-
-const client = new SolrouterAgentClient({ apiKey: "sk_solrouter_..." });
-
-const session = await client.swapOneshot({
- payerPubkey: "...",
- fromMint: "So11111111111111111111111111111111111111112", // SOL
- toMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
- amount: "10000000",
- destinationPubkey: "...", // fresh address — no on-chain link to payer
-});
-
-// Sign session.fundingTx with your wallet, broadcast, then:
-await client.swapOneshotExecute(session.sessionId, fundingTxSig);
-const settled = await client.pollUntilSettled(session.sessionId);
-```
-
-## Authentication modes
-
-How your agent proves it can pay shapes how you deploy it, so pick the model that fits before you build. The Agent Privacy API supports two.
-
-* **API key** — Include `Authorization: Bearer sk_solrouter_...` in every request. Usage bills against your prepaid balance in USDC or `$ROUTER`. Best when your agent is long-lived and you've already funded an account.
-* **x402 (keyless)** — Pay per call in USDC on Solana mainnet through the Coinbase facilitator, with no account at all. Discover pricing and payment endpoints at [`/.well-known/x402`](https://solrouter.com/.well-known/x402).
-
-
- x402 is ideal for agents that operate without a pre-registered API key — for example, autonomous agents that spin up on demand and pay for exactly the calls they make. No balance top-up or account creation required.
-
-
-## Available tools
-
-These are the building blocks your agent can call, whether through `aiSdkTools()` or the raw `TOOLS` / `callTool()` exports. Each one maps to a single step of the private-swap or encrypted-inference flow.
-
-| Tool | Description |
-| ---------------------------- | ------------------------------------------------------ |
-| `umbra_quote` | Quote a private swap with anonymity-set sizing |
-| `umbra_anonymity_set` | Inspect current anonymity set for a mint pair |
-| `umbra_swap_oneshot` | One-shot swap session — agent signs funding tx |
-| `umbra_swap_oneshot_execute` | Submit signed funding tx to start execution |
-| `umbra_session_status` | Poll session state until `settled` |
-| `umbra_create_wallet` | Provision a managed Umbra wallet for an agent |
-| `umbra_swap_managed` | Run a swap from a managed wallet |
-| `umbra_encrypt` | Convert balance to encrypted balance on same wallet |
-| `umbra_shield` | Mixer round-trip → withdraw → forward to fresh address |
-| `umbra_balance` | Read encrypted balance of a managed wallet |
-| `umbra_attestation` | Fetch the on-chain attestation PDA for a session |
-| `private_inference_paid` | x402-paywalled encrypted inference (no API key) |
diff --git a/content/docs/develop/authentication.mdx b/content/docs/develop/authentication.mdx
deleted file mode 100644
index b941fd0..0000000
--- a/content/docs/develop/authentication.mdx
+++ /dev/null
@@ -1,99 +0,0 @@
----
-title: "Authentication"
-icon: KeyRound
-description: "Solrouter uses bearer token authentication. Generate an API key at solrouter.com/sdk by connecting a Solana wallet — no email or KYC required."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Step, Steps } from 'fumadocs-ui/components/steps';
-
-Most AI APIs make you sign up with an email, verify your identity, and hand over a credit card before you can send a single request. Solrouter skips all of that. You authenticate with an API key passed as a bearer token, and you get that key by connecting a Solana wallet — no email sign-up, no KYC (Know Your Customer identity checks), no card.
-
-Fund a prepaid balance in USDC or \$ROUTER, and you're making calls in minutes.
-
-## Getting your API key
-
-Here's the full path from zero to your first authenticated request — four steps, all in the browser.
-
-
-
-### Go to solrouter.com/sdk
-
-Open [solrouter.com/sdk](https://solrouter.com/sdk) in your browser.
-
-
-
-### Connect your Solana wallet
-
-Connect any compatible Solana wallet (e.g. Phantom, Backpack, Solflare). Your wallet is your only identity credential — Solrouter collects no email and no personal information.
-
-
-
-### Generate an API key
-
-Click **Generate API Key**. Your key is issued immediately and starts with `sk_solrouter_...`. Copy it and store it somewhere safe — it won't be shown again.
-
-
-
-### Top up your balance
-
-Add funds to your prepaid account in **USDC** or **\$ROUTER**. Solrouter meters every API call per request and deducts the cost from this balance, so there's no monthly bill — you pay only for what you use.
-
-
-
-## Using your API key
-
-Once you have a key, you attach it to requests in one of two ways: through the SDK, which handles it for you, or directly over HTTP.
-
-### With the SDK
-
-Pass your API key when you create the `SolRouter` client. From then on, the SDK attaches it to every request automatically — you never touch the header yourself.
-
-```typescript
-import { SolRouter } from '@solrouter/sdk';
-
-const client = new SolRouter({ apiKey: 'sk_solrouter_...' });
-```
-
-### Direct HTTP (REST API)
-
-If you're not using the SDK, send the key yourself as a bearer token in the `Authorization` header.
-
-```bash
-curl -X POST "https://api.solrouter.com/agent" \
- -H "Authorization: Bearer sk_solrouter_..." \
- -H "Content-Type: application/json" \
- -d '{"prompt": "Hello", "model": "gpt-oss:20b"}'
-```
-
-## Authentication tiers
-
-Solrouter offers three ways to authenticate, each suited to a different kind of caller. Pick the row that matches how your code runs.
-
-| Tier | How it works | Best for |
-| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
-| **API key** | `Authorization: Bearer sk_solrouter_...`, billed from your prepaid balance | Most applications and development workflows |
-| **x402 (keyless)** | Per-call USDC settlement on Solana mainnet via Coinbase facilitator. Service discovery at [`/.well-known/x402`](https://solrouter.com/.well-known/x402) | Autonomous agents that don't hold API keys |
-| **Internal JWT** | Short-lived JWT issued to Solrouter's own first-party products | Solrouter-hosted products only; not available to external developers |
-
-The x402 tier is worth a closer look if you're building agents: instead of provisioning and storing a long-lived key, an agent pays for each call on the spot in USDC. That means it can authenticate and transact entirely on-chain, with no secret to leak.
-
-## Keeping your API key safe
-
-Your key can spend real money, so treat it with the same care as a password. The practices below keep it out of the wrong hands.
-
-* **Never commit your API key to source control.** Treat `sk_solrouter_...` like a password — keep it out of Git history, `.env` files that are checked in, and any public repository.
-
-* **Use environment variables.** Store your key in `SOLROUTER_API_KEY` and read it at runtime so the secret never lives in your code:
-
- ```typescript
- const client = new SolRouter({
- apiKey: process.env.SOLROUTER_API_KEY
- });
- ```
-
-* **Rotate compromised keys immediately.** If a key is exposed, go to [solrouter.com/sdk](https://solrouter.com/sdk), revoke the affected key, and generate a new one.
-
-
- Never expose your API key in client-side code or public repositories. Anyone with your key can spend your prepaid balance. If you suspect a key has been leaked, rotate it immediately at solrouter.com/sdk.
-
diff --git a/content/docs/develop/mcp-server.mdx b/content/docs/develop/mcp-server.mdx
deleted file mode 100644
index e077ec0..0000000
--- a/content/docs/develop/mcp-server.mdx
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "MCP Server"
-icon: Plug
-description: "Use Solrouter's encrypted AI and private swap tools directly from Claude Desktop or Cursor by installing the @solrouter/mcp-server MCP integration."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-
-You already work inside Claude Desktop or Cursor. The Solrouter MCP server lets you run Solrouter's encrypted AI and Agent Privacy API tools right there — no separate app, no copy-paste between windows.
-
-MCP (Model Context Protocol — an open standard for connecting AI clients to external tools) is the bridge. Once you wire up the server, every tool call — research, token analysis, private swaps — runs through the same end-to-end encrypted pipeline as the SDK. Your queries stay private even though they start in your editor or desktop assistant.
-
-## Configuration
-
-This is the one-time setup that registers Solrouter as a tool provider in your client.
-
-Add the following block to your MCP configuration file. For **Claude Desktop**, that file is `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS (or the equivalent path on Windows). For **Cursor**, add it under `mcpServers` in your Cursor settings JSON (`~/.cursor/mcp.json`).
-
-```json
-{
- "mcpServers": {
- "solrouter": {
- "command": "npx",
- "args": ["@solrouter/mcp-server"],
- "env": {
- "SOLROUTER_API_KEY": "sk_solrouter_..."
- }
- }
- }
-}
-```
-
-Save the config, then restart Claude Desktop or reload the Cursor window. The Solrouter tools appear in the tool list automatically — nothing else to install.
-
-## Privacy and research tools
-
-Use these tools when you want encrypted AI inference or on-chain research from inside your client.
-
-| Tool | Description |
-| ------------------------ | --------------------------------------------------------------------- |
-| `private_research` | Encrypted multi-source research (web + DEX + on-chain + AI synthesis) |
-| `encrypted_chat` | Direct E2E encrypted AI query |
-| `private_token_analysis` | Comprehensive encrypted token research |
-| `private_wallet_audit` | Encrypted wallet intelligence |
-| `list_models` | Available models with pricing |
-| `account_balance` | USDC + `$ROUTER` credit balance |
-
-## Agent Privacy API tools
-
-When you need to move funds privately — quoting, executing, and managing swaps — reach for these. They expose the full Solrouter Agent Privacy API, including private swap execution and managed wallet operations.
-
-| Tool | Description |
-| ---------------------------- | ------------------------------------------------------ |
-| `umbra_quote` | Quote a private swap with anonymity-set sizing |
-| `umbra_anonymity_set` | Inspect current anonymity set for a mint pair |
-| `umbra_swap_oneshot` | One-shot swap session — agent signs funding tx |
-| `umbra_swap_oneshot_execute` | Submit signed funding tx to start execution |
-| `umbra_session_status` | Poll session state until `settled` |
-| `umbra_create_wallet` | Provision a managed Umbra wallet for an agent |
-| `umbra_swap_managed` | Run a swap from a managed wallet |
-| `umbra_encrypt` | Convert balance to encrypted balance on same wallet |
-| `umbra_shield` | Mixer round-trip → withdraw → forward to fresh address |
-| `umbra_balance` | Read encrypted balance of a managed wallet |
-| `umbra_attestation` | Fetch the on-chain attestation PDA for a session |
-| `private_inference_paid` | x402-paywalled encrypted inference (no API key) |
-
-
- Every request through the MCP server is end-to-end encrypted with the same Arcium RescueCipher + Intel TDX pipeline as the Privacy SDK. Your prompt starts in Claude Desktop or Cursor, but Solrouter's backend never sees the plaintext — only the enclave does.
-
diff --git a/content/docs/develop/privacy-sdk.mdx b/content/docs/develop/privacy-sdk.mdx
deleted file mode 100644
index 4f088fd..0000000
--- a/content/docs/develop/privacy-sdk.mdx
+++ /dev/null
@@ -1,106 +0,0 @@
----
-title: "Privacy SDK"
-icon: Code
-description: "Add end-to-end encrypted AI to any app in minutes. Install @solrouter/sdk, pass your API key, and call client.chat() — encryption handled automatically."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
-
-Most AI APIs read your prompts in the clear. The Solrouter Privacy SDK is built so that no one — not even Solrouter — can. It handles encryption for you, so you never have to wire up cryptography yourself.
-
-Here is what happens when you call `client.chat()`. The SDK fetches the attested X25519 public key from the TEE (Trusted Execution Environment — hardware that isolates code and data even from the machine's owner), then encrypts your prompt on your machine using Arcium's RescueCipher. It sends the encrypted blob through the Solrouter backend, which routes it blindly — the backend cannot decrypt it. The response comes back encrypted and the SDK decrypts it with your ephemeral session key. Your plaintext prompt and response exist only on your machine and inside the Intel TDX enclave — nowhere else.
-
-## Installation
-
-Install the SDK from your package manager of choice.
-
-
-
- ```bash
- npm install @solrouter/sdk
- ```
-
-
- ```bash
- yarn add @solrouter/sdk
- ```
-
-
- ```bash
- pnpm add @solrouter/sdk
- ```
-
-
-
-## Basic usage
-
-This section walks through the calls you will make most often, starting with the default encrypted chat.
-
-### Encrypted chat (default)
-
-You get end-to-end encryption with zero setup — every call is encrypted unless you opt out. Instantiate `SolRouter` with your API key and start chatting.
-
-```typescript
-import { SolRouter } from '@solrouter/sdk';
-
-const client = new SolRouter({ apiKey: 'sk_solrouter_...' });
-
-// Encrypted end-to-end. Solrouter backend never sees plaintext.
-const response = await client.chat('What are the risks of this DeFi protocol?');
-console.log(response.message);
-```
-
-### Choosing a model
-
-Solrouter runs two self-hosted models. Pick one with the `model` option; leave it out to use the default.
-
-```typescript
-const response = await client.chat('Summarize the latest Solana validator outage', {
- model: 'gpt-oss-20b', // gpt-oss-20b (default) | qwen3-8b
-});
-```
-
-### Opt out of encryption (faster, plaintext)
-
-Encryption adds a little latency. When a query isn't sensitive and you want it back faster, disable client-side encryption for that single call.
-
-```typescript
-const response = await client.chat('Hello', { encrypted: false });
-```
-
-### SERV-guided reasoning (agent path)
-
-For questions that need structured analysis rather than a single freeform answer, route through the agent endpoint. Setting `reasoning: 'braid'` runs your request through SERV guided reasoning — a deterministic execution graph that replaces freeform LLM decision-making with structured, tool-augmented steps.
-
-```typescript
-const response = await client.chat('Compare Marginfi vs Kamino lending on Solana', {
- reasoning: 'braid', // routes through agent endpoint with guided reasoning
-});
-```
-
-### Check balance
-
-You pay per call from a prepaid balance. Check what's left at any time.
-
-```typescript
-const { balance, balanceFormatted } = await client.getBalance();
-```
-
-## SDK options reference
-
-Each of these options goes in the object you pass as the second argument to `client.chat()`.
-
-| Option | Type | Default | Description |
-| ----------- | ------- | ------------- | ------------------------------------------ |
-| `model` | string | `gpt-oss-20b` | Model to use: `gpt-oss-20b` or `qwen3-8b` |
-| `encrypted` | boolean | `true` | Enable/disable client-side encryption |
-| `reasoning` | string | — | Set to `'braid'` for SERV-guided reasoning |
-
-## No KYC required
-
-Privacy starts at sign-up: there's nothing to identify you. You don't need an email address, credit card, or any personal information to use the SDK. Connect your Solana wallet at [solrouter.com/sdk](https://solrouter.com/sdk), generate an API key, and top up your balance in USDC or `$ROUTER`. Pricing is metered per call from your prepaid balance.
-
-
- Solrouter runs only self-hosted, open-weight models (`gpt-oss:20b` and `qwen3:8b`) on the Nosana decentralized GPU network. There are no third-party model APIs — no OpenAI, Anthropic, or Google. Your prompts and documents never leave to an external model provider.
-
diff --git a/content/docs/develop/private-swaps.mdx b/content/docs/develop/private-swaps.mdx
deleted file mode 100644
index d52aaf4..0000000
--- a/content/docs/develop/private-swaps.mdx
+++ /dev/null
@@ -1,124 +0,0 @@
----
-title: "Private Swaps"
-icon: ArrowRightLeft
-description: "The /agents/v1 API lets AI agents execute privacy-preserving token swaps on Solana through two modes: managed wallets and one-shot transactions."
----
-
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
-
-When an autonomous agent moves tokens on Solana, the transaction graph exposes who paid whom. Anyone can trace the link between the funding source and the destination. The Agent Privacy API (`/agents/v1`) exists to break that link.
-
-This is a dedicated, agent-first surface for two things: privacy-preserving on-chain actions and encrypted inference. The main Solrouter SDK covers encrypted chat and research; this API is purpose-built for agents that need to swap tokens privately, and for keyless agents that pay per inference call via x402 (a pay-per-request HTTP standard) instead of holding a pre-funded API key.
-
-Every action here runs through the same Intel TDX-isolated enclave — hardware that keeps code and data sealed even from the machine's owner — and the same Arcium-encrypted transport as the rest of Solrouter's infrastructure.
-
-## Execution modes
-
-How you run a private swap depends on one question: does your agent keep its own funded wallet with Solrouter, or does it sign each operation on the fly? The API supports both. Pick the mode that matches how your agent already works.
-
-
-
- Use this mode when you want to fund once and forget the setup. Your agent provisions a long-lived encrypted-balance wallet through the API, funds it a single time, then runs as many private swaps as it needs — no repeated wallet provisioning.
-
- **How custody works:**
-
- * The per-wallet Data Encryption Key (DEK) is envelope-encrypted with a KMS-held Key Encryption Key (KEK)
- * The DEK is never persisted in plaintext — it exists only inside the enclave during an active operation
- * Your agent interacts with the wallet through authenticated API calls; the underlying key material never leaves the TEE
-
- **When to use it:** agents that run frequent swaps, need to accumulate balance over time, or operate on a recurring schedule. The managed wallet removes the overhead of signing a new funding transaction on every operation.
-
- ```typescript
- import { SolrouterAgentClient } from "@solrouter/agent-tools";
-
- const client = new SolrouterAgentClient({
- apiKey: process.env.SOLROUTER_API_KEY,
- });
-
- // Provision a managed wallet for this agent
- const wallet = await client.createWallet();
-
- // Run a swap from the managed wallet — no funding tx required
- // (walletId is the first positional argument)
- const swap = await client.swapManaged(wallet.walletId, {
- fromMint: "So11111111111111111111111111111111111111112", // SOL
- toMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
- amount: "10000000",
- destinationPubkey: "YOUR_FRESH_DESTINATION_ADDRESS",
- });
- ```
-
-
-
- Use this mode when your agent already has its own wallet and you'd rather not hold a balance with Solrouter. Nothing is provisioned: your agent receives an unsigned funding transaction, signs it with its own wallet, submits the signature, and the orchestrator handles the rest.
-
- **The 7-step pipeline:**
-
- 1. Agent requests a one-shot session, providing payer pubkey, mints, amount, and destination
- 2. API returns an unsigned funding transaction
- 3. Agent signs the transaction with its own wallet and broadcasts it
- 4. Agent submits the transaction signature to the API to start execution
- 5. Orchestrator runs the mixer round-trip to break the on-chain link
- 6. Jupiter aggregator executes the swap at best available price
- 7. Proceeds are forwarded to the destination address — with no on-chain connection to the original payer
-
- ```typescript
- import { SolrouterAgentClient } from "@solrouter/agent-tools";
-
- const client = new SolrouterAgentClient({ apiKey: "sk_solrouter_..." });
-
- const session = await client.swapOneshot({
- payerPubkey: "YOUR_AGENT_WALLET_PUBKEY",
- fromMint: "So11111111111111111111111111111111111111112", // SOL
- toMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
- amount: "10000000",
- destinationPubkey: "FRESH_DESTINATION_ADDRESS",
- });
-
- // Sign session.fundingTx with your wallet and broadcast
- // Then submit the confirmed signature:
- await client.swapOneshotExecute(session.sessionId, fundingTxSig);
-
- // Poll until the full pipeline settles
- const settled = await client.pollUntilSettled(session.sessionId);
- ```
-
- **When to use it:** stateless agents, single-operation workflows, or any agent that already manages its own wallet and prefers not to maintain a separate funded balance with Solrouter.
-
-
-
-## Discovery endpoints
-
-So your agent doesn't have to hardcode URLs, the API publishes its own configuration. A2A-compatible agents (the Agent-to-Agent interop protocol) and x402-aware runtimes read these endpoints to self-configure at runtime.
-
-| Endpoint | Description |
-| ------------------------------ | ---------------------------------------------------------------- |
-| `/.well-known/agent-card.json` | A2A protocol v1.0 card with the full skill list |
-| `/.well-known/x402` | x402 paywall manifest — per-call USDC pricing for keyless agents |
-| `/agents/v1/openapi.json` | Full OpenAPI 3.1 specification |
-| `/agents/v1/capabilities` | Capability summary for runtime introspection |
-
-## x402 encrypted inference
-
-Not every agent has an API key, and account creation is friction you may not want. For those cases Solrouter exposes a pay-per-call encrypted inference endpoint built on the pay.sh x402 standard: your agent pays in USDC on Solana mainnet, with no account and no key management.
-
-* **Endpoint:** `POST /api/v1/x402/chat/completions`
-* **Pricing:** \$0.005 per call, settled via x402 USDC on Solana mainnet
-* **Encryption:** Arcium-encrypted prompt in, encrypted response out — the same TEE-isolated path as the SDK
-* **Discovery:** `/.well-known/x402` — any x402-aware agent runtime can auto-discover pricing and payment instructions
-
-```bash
-# x402 paywalled encrypted inference — no API key needed.
-# `encryptedPrompt` MUST be an Arcium ciphertext produced client-side
-# (use @solrouter/sdk's encryptPrompt() helper); `model` is required.
-curl -X POST "https://api.solrouter.com/api/v1/x402/chat/completions" \
- -H "Content-Type: application/json" \
- -d '{"encryptedPrompt": "", "model": "gpt-oss:20b"}'
-```
-
-When an x402-aware runtime calls this endpoint, it negotiates and settles payment for you automatically. Call it directly without completing the payment handshake and the server replies with `402 Payment Required`, returning the payment terms in the `X-Payment` header so you can pay and retry.
-
-
- Each privacy-mode session can publish a Program Derived Address (PDA) on Solana mainnet, anchored to the Solrouter encryption-attestation program at `ATMRatMtsKX4bHax7U4FRdhbE4mjU4NKpDZGqZqAhBKb`. The PDA links this specific request to the attested TEE, providing on-chain proof that the interaction was processed inside a verified Intel TDX enclave — something you or any third party can verify independently.
-
diff --git a/content/docs/glossary.mdx b/content/docs/glossary.mdx
new file mode 100644
index 0000000..09a86d8
--- /dev/null
+++ b/content/docs/glossary.mdx
@@ -0,0 +1,132 @@
+---
+title: "Glossary"
+icon: BookA
+description: "Plain-language definitions of every term used in these docs, in alphabetical order, each with a link to the page that explains it."
+status: live
+checked: "2026-08-26"
+statusNote: "Definitions match the code and live API on the checked date. Where a term names a feature, its status (Live, Soon, Archived) is in the entry."
+---
+
+This page defines each term in plain words first, then the technical name. Every entry links to the page that explains it in full. Some entries use an analogy and say where it stops being accurate.
+## A
+**A2A agent card.** A small public file that lists what an AI agent can do, in a format other agents read. Solrouter serves one at `/.well-known/agent-card.json` (Live). See [Discovery documents](/docs/api-reference/overview).
+
+**/agent endpoint.** The address (`POST /agent`) where a program sends a research question and gets a tool-built answer. By default it runs a tool loop: the model picks a tool, runs it, and repeats up to 8 times. See [Agent endpoint and guided reasoning](/docs/how-it-works/agent-reasoning).
+
+**Agent Privacy API.** A separate set of endpoints under `/agents/v1` for autonomous software agents. It covers private token swaps (Soon) and pay-per-call encrypted answers with no account (Live). It is not the `/agent` endpoint above. See [Agent Privacy API](/docs/build/agent-privacy-api).
+
+**Agent Tools SDK.** A planned code package, `@solrouter/agent-tools`, that would wrap the Agent Privacy API. It is not on npm yet (Soon). See [Agent Tools SDK](/docs/build/agent-tools-sdk).
+
+**Anonymity set.** The group of deposits a mixer cannot tell apart from yours. A bigger group gives more privacy. `GET /agents/v1/anonymity-set` reports the size for an amount bucket (Live). See [Private swaps internals](/docs/build/agent-privacy-api).
+
+**API key.** A secret string that starts with `sk_solrouter_`. Send it with a request so Solrouter knows which prepaid balance to charge. Treat it like a password. See [Get an API key](/docs/build/api-key).
+
+**Arcium.** The company whose software library Solrouter uses to encrypt prompts on your device. The chat app labels this "encrypted with Arcium". Arcium also runs a network for computing on encrypted data, which Solrouter does not use for inference today. See [RescueCipher and X25519](/docs/how-it-works/encryption).
+
+**Attestation.** A signed statement from the computer chip. It says a real Intel chip runs this sealed program, and the program owns this public key. Think of it as a tamper-evident seal. The seal proves the hardware and the key. Solrouter has not published reference values, so you cannot yet prove which program image is inside. See [What is a TEE?](/docs/how-it-works/what-is-a-tee) and [TDX attestation](/docs/how-it-works/attestation).
+## B
+**Backend.** The ordinary Solrouter servers that receive your request, charge your balance, and forward the encrypted message to the enclave. On the encrypted path the backend holds no key and cannot read your prompt. It is a blind courier. See [What is private here](/docs/use/what-is-private).
+
+**BRAID.** Solrouter's guided reasoning feature. A normal agent asks the model what to do at each step. BRAID instead follows a fixed plan (a GRD), gathers data with tools, then calls the model once to write the answer. Request it with `reasoning: 'braid'`. Older material calls this SERV. See [Agent endpoint and guided reasoning](/docs/how-it-works/agent-reasoning).
+## C
+**Ciphertext and plaintext.** Plaintext is text anyone can read. Ciphertext is the scrambled form that only a key holder can turn back into text. On the encrypted path your prompt leaves your device as ciphertext. See [What is private here](/docs/use/what-is-private).
+
+**Confidential VM (CVM).** A virtual computer whose memory the chip encrypts, so the owner of the physical machine cannot look inside. Solrouter's enclave is a CVM on Intel TDX hardware hosted by Phala. See [What is a TEE?](/docs/how-it-works/what-is-a-tee).
+## D
+**DEK and KEK.** Two keys for managed swap wallets. The DEK (data encryption key) locks one wallet's secret. The KEK (key encryption key) is a wrapping key the backend holds, and it locks the DEK. Both are handled in the backend process, not the enclave. See [Private swaps internals](/docs/build/agent-privacy-api).
+
+**Discovery documents.** Public files a program can fetch to learn what Solrouter offers and what each call costs. They include the A2A agent card, the x402 manifest, an OpenAPI file (a machine-readable list of endpoints), and `/agents/v1/capabilities`. All are Live. See [Discovery documents](/docs/api-reference/overview).
+## E
+**ed25519 signature.** A digital signature scheme. The enclave creates an ed25519 signing key at boot and signs the encryption proof for each private reply. The signature lets anyone check that the enclave, not the backend, produced the receipt. See [On-chain encryption proof](/docs/how-it-works/proof).
+
+**Enclave.** The sealed program that decrypts your prompt. In these docs "enclave" and "Confidential VM" mean the same running service. Picture a locked room with one mail slot: encrypted letters in, encrypted replies out. The analogy breaks here: the enclave sends your decrypted prompt to a GPU computer outside the room to run the model. See [What is a TEE?](/docs/how-it-works/what-is-a-tee).
+
+**Encryption proof.** A receipt for one private reply, written to the Solana blockchain. The enclave signs a summary of your encrypted prompt, and Solrouter stores it in a compressed account. Anyone with the lock link can check it. It proves the enclave handled that exact ciphertext, not what the model said. See [Check a reply yourself](/docs/verify).
+## F
+**Facilitator (x402).** The third-party service that checks and settles a pay-per-call payment. In production the manifest names Coinbase's facilitator. See [x402 payments](/docs/build/api-key).
+
+**FDV (fully diluted valuation).** The value of every token that will ever exist, at today's price. Solrouter's fundraising sells tokens in steps tied to FDV bands. See [$ROUTER token](/docs/token).
+
+**FHE, MPC, and ZK.** Three families of maths for working with data while it stays encrypted. Solrouter does not use any of them to run the model today. It chose the cipher so a future move in that direction would not change the client side. See [RescueCipher and X25519](/docs/how-it-works/encryption).
+## G
+**GRD (Guided Reasoning Diagram).** A fixed plan for one kind of question. It tells BRAID which tools to run and in what order. Six exist: comparison, DeFi analysis, general research, market overview, token research, and wallet analysis. See [Agent endpoint and guided reasoning](/docs/how-it-works/agent-reasoning).
+
+**Guest mode.** Using the chat app without a wallet. Guests get 5 free messages per day per network address. See [Chat app](/docs/use/chat-app).
+## I
+**Intel DCAP.** Intel's free software for checking that a TDX quote came from real Intel hardware. A security researcher can run it against the quote Solrouter returns. See [Check a reply yourself](/docs/verify).
+
+**Intel TDX.** The Intel chip feature that creates Confidential VMs and signs attestation quotes. TDX stands for Trust Domain Extensions. Solrouter's enclave reports its type as `INTEL-TDX-PHALA`. See [What is a TEE?](/docs/how-it-works/what-is-a-tee).
+## J
+**Jupiter.** A Solana service that finds the best price across many exchanges for a token swap. The private swap worker uses Jupiter for the swap step (Soon). See [Private swaps internals](/docs/build/agent-privacy-api).
+## L
+**Lamports.** The smallest unit of SOL, Solana's native coin. One SOL is one billion lamports. API amounts use these base units, so `10000000` means 0.01 SOL. See [Agent Privacy API](/docs/build/agent-privacy-api).
+
+**Light Protocol compressed account.** A cheap record on the Solana blockchain. Solrouter stores each encryption proof in one. Older material called this record a "PDA"; the current record is a compressed account. Its address comes from the hash of your ciphertext. See [On-chain encryption proof](/docs/how-it-works/proof).
+
+**Liquidity pool.** A shared pot of two tokens on an exchange that lets people trade one for the other at any time. Part of the $ROUTER supply is placed in one at launch. See [$ROUTER token](/docs/token).
+## M
+**Managed wallet (Mode A).** A swap mode where Solrouter creates and holds a wallet for your agent. You fund it once and run swaps from it. Solrouter holds the key, so this is custody, not self-custody. Swap execution is Soon. See [Agent Privacy API](/docs/build/agent-privacy-api).
+
+**Maximum Privacy Mode.** A chat app setting. When on, your messages are encrypted on your device and never stored. Refresh the page and the conversation is gone. It is off by default. See [Chat app](/docs/use/chat-app).
+
+**MCP (Model Context Protocol).** A standard that lets desktop AI apps such as Claude Desktop or Cursor call outside tools. Solrouter's MCP server adds its tools to those apps (Live). Only some of those tools use the encrypted path. See [MCP server](/docs/build/mcp-server).
+
+**Memory (wallet-encrypted).** A chat app feature that remembers facts across conversations. The facts are encrypted with a key made from your wallet's signature, so only your wallet can unlock them. The backend stores only the sealed form. See [Chat app](/docs/use/chat-app).
+
+**Mint address.** The unique on-chain address that identifies one token type on Solana, such as USDC or $ROUTER. Swap requests name tokens by mint address. See [Agent Privacy API](/docs/build/agent-privacy-api).
+
+**Mixer.** A shared on-chain pool that breaks the link between the wallet that puts money in and the one that takes it out. Picture people dropping same-size envelopes into one box, then each taking one out. The analogy breaks here: using the box is public, and amounts at the edges of the pool are visible. Solrouter uses the Umbra mixer (Soon). See [Private swaps internals](/docs/build/agent-privacy-api).
+## N
+**Nonce.** A random number used once per encrypted message, so two identical prompts never make the same ciphertext. The nonce is stored in the encryption proof. See [RescueCipher and X25519](/docs/how-it-works/encryption).
+
+**Nosana GPU node.** A rented computer with a graphics card on the Nosana network. It runs the AI model. The enclave sends it your decrypted prompt over an encrypted connection. The model runs outside the enclave, so the node operator could read the prompt at that moment. Solrouter does not control that hardware, and the request is not tied to your identity there. See [What is private here](/docs/use/what-is-private).
+
+**Nosana job.** One running task on the Nosana network. Solrouter runs each model as its own job, so each model has its own node and address. After idle time a node can answer "Nosana GPU node is warming up"; wait and retry. See [Models and Nosana nodes](/docs/how-it-works/models).
+## O
+**Ollama.** Free software that runs open-weight models and answers requests in the common OpenAI format. Each Nosana node runs Ollama to serve its model. See [Models and Nosana nodes](/docs/how-it-works/models).
+
+**One-shot swap (Mode B).** A swap mode where your agent keeps its own wallet. Solrouter returns an unsigned funding transaction, your agent signs it, and a worker does the rest. Swap execution is Soon. See [Agent Privacy API](/docs/build/agent-privacy-api).
+
+**Open-weight model.** An AI model whose files are public, so anyone can download and run it on their own hardware. This is what makes private hosting possible. Solrouter runs `gpt-oss:20b` (Live), `qwen3.8:27b` (Live), and `gemma4:31b` (Soon). See [Models and Nosana nodes](/docs/how-it-works/models).
+## P
+**Persistent Privacy Mode.** The chat app default. Messages are encrypted for transport, then saved so your history survives a reload. Saved history is encrypted at rest with a key the backend holds. That protects against a stolen database copy, but does not hide history from Solrouter. See [Chat app](/docs/use/chat-app).
+
+**Phala dStack.** The hosting platform that runs Solrouter's Confidential VM on Intel TDX hardware. It also provides the small service (tappd) that hands out attestation quotes. See [TDX attestation](/docs/how-it-works/attestation).
+
+**Plaintext mode.** Sending a prompt with `encrypted: false` in the SDK. The prompt travels unencrypted through the backend to the same models. You give up every privacy guarantee, and it unlocks no other model. See [Privacy SDK](/docs/build/privacy-sdk).
+
+**Prepaid balance.** Money you add to your Solrouter account before use, in USDC or $ROUTER. Each call deducts from it. Adding money is called a top-up. See [Pricing and balance](/docs/use/pricing).
+## Q
+**Quote (TDX quote).** The signed attestation document produced by the Intel chip through Phala's dStack service. Its `report_data` field pins the enclave's public key. `GET /tee/attestation` returns one (Live). A reply's quote is `null` with a `tdxQuoteError` when the enclave cannot reach dStack. See [TDX attestation](/docs/how-it-works/attestation).
+## R
+**RAG (retrieval-augmented generation).** Asking questions over your own uploaded documents. The chat app splits documents into pieces and finds the relevant pieces before the model answers. Those pieces are stored unencrypted on the backend. See [Chat app](/docs/use/chat-app) and [Data at rest](/docs/use/what-is-private).
+
+**report_data.** A 64-byte field inside a TDX quote that the enclave fills before the chip signs it. Solrouter puts a hash of its public key there. Two formulas exist: `GET /tee/attestation` pins the X25519 key alone, and per-reply quotes pin the X25519 key with the ed25519 signing key. See [TDX attestation](/docs/how-it-works/attestation).
+
+**RescueCipher.** The cipher (scrambling method) from Arcium that Solrouter uses to encrypt your prompt on your device. It works on numbers in a mathematical field instead of raw bytes, so the SDK packs 31 bytes into each number. See [RescueCipher and X25519](/docs/how-it-works/encryption).
+
+**$ROUTER.** Solrouter's own token on Solana. You can pay for calls with it instead of USDC. Solrouter can buy it back and burn it with revenue; the configured ratios are not published. See [$ROUTER token](/docs/token).
+## S
+**SERV.** The older name for the guided reasoning feature now called BRAID. It is not the "OpenServ" line in the token allocation table, which names a token drop to that community. See [Agent endpoint and guided reasoning](/docs/how-it-works/agent-reasoning).
+
+**Skill graph.** A set of 44 linked notes with expert knowledge on Solana, DeFi, and research method. When your question matches a note's trigger words, the `/agent` endpoint adds that note to the model's instructions. It runs on the plaintext path only. See [Agent endpoint and guided reasoning](/docs/how-it-works/agent-reasoning).
+
+**Solana wallet.** An app that holds your Solana keys and signs actions for you. Solrouter uses your wallet as your login, with no email and no identity check. Phantom, Solflare, or a Privy embedded wallet all work. See [Get an API key](/docs/build/api-key).
+## T
+**tappd.** The small program inside a Phala dStack CVM that asks the Intel chip for a quote. Solrouter's enclave talks to it over a local socket. When the socket is missing, quote requests fail with `tdx_quote_unavailable`. See [TDX attestation](/docs/how-it-works/attestation).
+
+**TEE (Trusted Execution Environment).** A sealed area of a computer where code and data are hidden from the machine's owner. Solrouter's TEE is an Intel TDX Confidential VM. Picture a sealed room: the landlord owns the building but cannot see inside. The analogy breaks here: the model runs on a separate GPU computer outside the room. See [What is a TEE?](/docs/how-it-works/what-is-a-tee).
+
+**TGE (token generation event).** The moment a token first goes live and can be traded. Vesting schedules count from this date. See [$ROUTER token](/docs/token).
+## U
+**Umbra.** The Solana privacy protocol whose mixer Solrouter uses for private swaps (Soon). The MCP tools that start with `umbra_` move real funds. See [Private swaps internals](/docs/build/agent-privacy-api).
+
+**USDC.** A digital dollar on Solana, meant to stay worth one US dollar. Solrouter prices calls in USDC and accepts it for top-ups and pay-per-call payments. See [Pricing and balance](/docs/use/pricing).
+## V
+**Vesting (cliff and linear).** Rules for when locked tokens become spendable. A cliff is a waiting period with no release. Linear vesting then releases an equal amount at each step. See [$ROUTER token](/docs/token).
+## W
+**Wallet address.** The public name of a wallet, a long string of letters and numbers. You can share it to receive funds. It reveals nothing secret, but everything sent to it is visible on the public ledger. See [Get an API key](/docs/build/api-key).
+## X
+**X25519.** A method for two parties to agree on a shared secret key without ever sending it. Your device makes a fresh, single-use keypair per session and combines it with the enclave's public key. The enclave's key is made at boot and changes on every restart. It is also called the sealing key. See [RescueCipher and X25519](/docs/how-it-works/encryption).
+
+**x402.** A way to pay for one web request at the moment you make it, using HTTP status code 402 ("payment required"). The server answers with a price, your agent pays in USDC, and the request goes through. No account or API key is needed. Encrypted x402 inference costs 0.005 USDC per call (Live). See [x402 payments](/docs/build/api-key).
diff --git a/content/docs/how-it-works/agent-reasoning.mdx b/content/docs/how-it-works/agent-reasoning.mdx
new file mode 100644
index 0000000..910ff9d
--- /dev/null
+++ b/content/docs/how-it-works/agent-reasoning.mdx
@@ -0,0 +1,69 @@
+---
+title: "Agent reasoning"
+icon: BrainCircuit
+description: "The three ways a request runs through POST /agent, the guided-reasoning path, and the skill graph that shapes the answer."
+status: live
+checked: "2026-08-26"
+---
+
+import { SkillGraphMap } from '@/components/diagrams/skill-graph-map';
+import { Callout } from 'fumadocs-ui/components/callout';
+
+`POST /agent` has three paths. The request body picks the path. Older material calls the guided path SERV; the code, the SDK option, and the API value call it BRAID.
+
+## Three paths
+
+| Path | Trigger | Where it runs | Model calls |
+| --- | --- | --- | --- |
+| Tool loop (default) | `useTools: true` | Backend | Up to 8 (`MAX_ITERATIONS = 8`) |
+| Guided reasoning (BRAID) | `reasoning: 'braid'` | Backend | One synthesis call |
+| Encrypted agent mode | `encryptedPrompt` | Inside the enclave | Loop inside the enclave |
+
+The encrypted path is Live for REST callers who send `encryptedPrompt`, and Soon for the SDK. The chat app's agent mode runs the plaintext tool loop.
+
+## The tool loop
+
+The default path is a standard loop. The model picks a tool, the backend runs it, the model reads the result, and it repeats up to eight times. The last call has no tools, so the model must write the answer. The backend registers 18 tools:
+
+- **Web:** `web_search`, `scrape_url`, `crawl_url`
+- **On-chain and markets:** `solana_balance`, `token_price`, `swap_quote`, `trending_tokens`
+- **Research:** `deepwiki`, `colosseum_search`, `colosseum_archives`
+- **Paid APIs:** `paysh_search_apis`, `paysh_call_api`
+- **Connected accounts:** `github_list_repos`, `github_issues`, `github_read_file`, `notion_search`, `notion_get_page`, `notion_query_database`
+
+The encrypted path runs a 5-tool allowlist inside the enclave: `web_search` (SearXNG in the same enclave), `token_price`, `trending_tokens`, `swap_quote`, and `solana_balance`. Every other tool fails closed in that mode.
+
+## Guided reasoning (BRAID)
+
+A standard loop asks the model what to do at every step, one model call per step. BRAID splits the two jobs an agent does: deciding what data to gather, and writing the answer. It walks a Guided Reasoning Diagram (GRD), a fixed graph that sets which tools run and in what order, then calls the model once at the end to write the reply.
+
+A query passes through four stages:
+
+1. **Intent detection.** Keyword rules map the prompt to one of six GRDs (`comparison`, `defi-analysis`, `general-research`, `market-overview`, `token-research`, `wallet-analysis`). No model call.
+2. **GRD execution.** BRAID walks the graph node by node. Branch nodes use a rule first; when no rule applies, the model answers a short one-word question to pick the branch.
+3. **Skill-graph injection.** If the prompt matches skill nodes, their notes are added to the synthesis prompt.
+4. **Synthesis.** BRAID calls the model once to turn the collected data into a reply.
+
+A swap prompt with two known tokens, or a prompt with three or more known tokens, skips the walk and calls the tools directly before the same single synthesis call.
+
+BRAID spends one synthesis call plus the occasional one-word branch call, instead of one model call per step. That is the whole mechanism behind the cost and latency claim. No benchmark numbers are published.
+
+
+ Send `reasoning: 'braid'` to `POST /agent`, or `client.chat(prompt, { reasoning: 'braid' })` in the SDK. The SDK path is plaintext today (`encrypted: false`). See [POST /agent](/docs/api-reference/agent) for the `braidTrace` envelope.
+
+
+## The skill graph
+
+Before the synthesis call, the engine matches your query against 44 knowledge nodes. It scores every node against the prompt, walks the graph from the top three scoring nodes, follows edges to a depth of 2, and stops at 5 nodes. The reached nodes add domain notes to the system prompt. A prompt that matches no node gets no extra tokens, and the response never returns the walked path.
+
+Click a node to see its edges. The highlighted path is a DeFi protocol comparison.
+
+
+
+**The 44 nodes, by cluster**
+
+- **Research and analysis (15):** research-core, source-eval, defi-analysis, liquidity-risk, token-economics, market-analysis, on-chain-analysis, wallet-analysis, privacy-research, risk-assessment, smart-contract-risk, comparative-analysis, data-synthesis, colosseum-research, colosseum-archives.
+- **Ecosystem (2):** arcium-mpc, solana-ecosystem.
+- **DeFi protocols (10):** jupiter-defi, raydium-defi, orca-defi, meteora-defi, kamino-defi, sanctum-staking, pump-fun, lulo-lending, ranger-perps, prediction-markets.
+- **Infrastructure and oracles (8):** helius-infra, light-protocol-zk, metaplex-nfts, pyth-oracle, switchboard-oracle, squads-multisig, debridge-cross-chain, coingecko-analytics.
+- **Solana development (9):** solana-kit-dev, anchor-dev, pinocchio-dev, framework-kit-frontend, solana-testing, solana-security-audit, token2022-extensions, quicknode-infra, magicblock-gaming.
diff --git a/content/docs/how-it-works/attestation.mdx b/content/docs/how-it-works/attestation.mdx
new file mode 100644
index 0000000..70ee855
--- /dev/null
+++ b/content/docs/how-it-works/attestation.mdx
@@ -0,0 +1,98 @@
+---
+title: "Attestation"
+icon: BadgeCheck
+description: "Fetch the Intel-signed TDX quote from the Solrouter enclave, check that it binds the key you encrypt to, and look up the on-chain receipt for each private inference."
+status: mixed
+checked: "2026-08-26"
+statusNote: "The quote endpoints and on-chain receipts are live. Reference measurements to compare against are not published yet."
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+import { Step, Steps } from 'fumadocs-ui/components/steps';
+
+When you send a prompt to a private inference service, how do you know it ran where the service claims? How do you know the code is the published code and not a tampered copy that logs your data? Solrouter answers that with attestation: hardware-signed proof you can check yourself.
+
+The Solrouter TEE (Trusted Execution Environment: hardware that isolates code and data even from the machine's owner) publishes an Intel-signed TDX quote. That quote binds the enclave's public key to the code measurement running inside the Confidential VM. Each `/tee/process` response also carries a quote when the CVM can reach the dStack agent. Otherwise the `attestation.tdxQuote` field is `null` and `attestation.tdxQuoteError` says why. You never have to take Solrouter's word for it: fetch the quote, verify Intel's signature chain, and confirm on-chain that your inference has a receipt.
+
+## Live attestation endpoints
+
+These two endpoints hand you the raw material for verification. Query them any time to retrieve the current attestation data.
+
+### Get the TEE public key
+
+```bash
+GET https://api.solrouter.com/tee/public-key
+```
+
+This returns the X25519 public key currently active inside the Confidential VM. The SDK uses this key to encrypt prompts client-side. The enclave generates it at boot, so only the enclave holds the matching private key. The key changes on every CVM boot. Nobody on the host, including Solrouter, can decrypt traffic sealed to it.
+
+### Get the TDX attestation quote
+
+```bash
+GET https://api.solrouter.com/tee/attestation
+```
+
+This returns the Intel TDX attestation quote, the hardware-signed proof that ties everything together. The response includes `teePublicKey`, `teePublicKeySha256`, `reportDataHex`, and `tdxQuote`. Its `report_data` is `sha256(teePublicKey)`, which binds the public key you fetched above to the enclave that produced the quote. Verify the quote and you confirm two things:
+
+1. The host CPU is a genuine Intel TDX-capable processor.
+2. The public key was generated inside that specific enclave instance.
+
+Confirming that the enclave runs the published Solrouter code needs reference measurements. Those are not published yet (see below).
+
+### Two report_data formulas
+
+Solrouter produces two kinds of quote. They pin different data, so check the right formula for the quote you hold.
+
+| Quote | `report_data` |
+| ------------------------------------------------ | ------------------------------------------ |
+| `GET /tee/attestation` | `sha256(X25519 public key)` |
+| `attestation.tdxQuote` in a `/tee/process` reply | `sha256(X25519 public key ‖ ed25519 public key)` |
+
+The ed25519 key is a signing key the enclave also generates at boot. The enclave uses it to sign the encryption proof that goes on-chain.
+
+## What you can verify
+
+Attestation only matters if you can check the claims independently. Here is what the quote lets you prove on your own today, and what it does not yet.
+
+* **Intel root chain**: the TDX quote is signed by an Intel-issued key. Verifying the signature chain confirms the hardware is a genuine TDX CPU, not a simulated or spoofed environment. Live.
+* **Public key binding**: `report_data` commits to the enclave's public key. So you can confirm the key you encrypted to belongs to this enclave instance. An interceptor cannot substitute its own key. Live.
+* **Code measurements**: the `tdxQuote` field is the dStack guest agent's response, passed through unparsed. Solrouter does not publish a parser or reference values for the measurements inside it. The product repository is private. Reference measurements: Soon.
+
+
+ Advanced users can verify the full Intel TDX quote chain independently using Intel's DCAP (Data Center Attestation Primitives) libraries or a third-party TEE verification service. The quote Solrouter returns is a standard TDX quote, no proprietary format.
+
+
+## On-chain attestation anchor
+
+Off-chain verification proves the enclave is genuine, but it lives in a response you have to trust Solrouter to keep. For a record nobody can quietly edit later, Solrouter anchors attestation data to Solana. Cluster: the commit code targets mainnet; the program deployment on mainnet has not been re-measured.
+
+The Solrouter attestation program is deployed at:
+
+```
+ATMRatMtsKX4bHax7U4FRdhbE4mjU4NKpDZGqZqAhBKb
+```
+
+Each inference sent through `POST /tee/process` gets a **Light Protocol compressed account** on Solana. Solrouter's deployer wallet commits it after the CVM signs the proof. This is automatic; you do not publish anything. The account address is derived from the seeds `attestation_v2` and `sha256(encryptedPrompt)`, so anyone who holds the ciphertext can derive the same address. The `/tee/process` response reports it under `onchainAttestation` with `address`, `signature`, and `explorerUrl`. If the commit fails, the inference still succeeds and `onchainAttestation` is `null`.
+
+To read a receipt back, use the public attestation endpoints. They read from the Solana ledger through a Photon indexer.
+
+```bash
+# By the commit transaction signature from onchainAttestation.signature
+GET https://api.solrouter.com/attestation/by-tx/:sig
+
+# By sha256 of the encrypted prompt
+GET https://api.solrouter.com/attestation/by-hash/:hash
+
+# By the compressed account address from onchainAttestation.address
+GET https://api.solrouter.com/attestation/:address
+
+# Derive hash and address from a ciphertext you hold
+POST https://api.solrouter.com/attestation/derive
+{ "encryptedPrompt": "..." }
+```
+
+The `umbra_attestation` MCP tool is a different thing. It returns the settlement record of a private-swap session from `GET /agents/v1/attestations/:sessionId`. It does not read inference receipts.
+
+## Verify it yourself
+
+The full check, from the live key through the Intel DCAP signature chain to the on-chain anchor, runs in your browser on [Check a reply yourself](/docs/verify). Auditors will find the by-hand steps there too.
diff --git a/content/docs/how-it-works/encryption.mdx b/content/docs/how-it-works/encryption.mdx
new file mode 100644
index 0000000..fc0b756
--- /dev/null
+++ b/content/docs/how-it-works/encryption.mdx
@@ -0,0 +1,102 @@
+---
+title: "Encryption"
+icon: Lock
+description: "Solrouter encrypts prompts on your device with Arcium RescueCipher and X25519 key exchange. Only an Intel TDX enclave can decrypt them. Solrouter's backend never sees plaintext."
+status: live
+checked: "2026-08-26"
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
+
+When you send a prompt to an AI provider, you normally trust that provider to read it, store it, and not misuse it. Solrouter removes that trust requirement for its own backend. Your prompt is encrypted on your own device before it leaves, and Solrouter's backend never holds the key to read it.
+
+Solrouter encrypts your prompts and responses with Arcium's `RescueCipher` cipher and `X25519` key exchange. X25519 lets two parties agree on a shared secret without sending it. The ciphertext travels through Solrouter's backend untouched. It is decrypted only inside a hardware-isolated Intel TDX Confidential VM, a TEE. A TEE (Trusted Execution Environment) is hardware that isolates code and data from the machine's owner. Solrouter's backend is a blind relay: it routes encrypted blobs it cannot read, and the private key that could decrypt them never leaves the enclave.
+
+## Encryption components
+
+Here are the three building blocks that make the guarantee work, and what each one does.
+
+### Client-side encryption
+
+The first line of defense is simple: encrypt before you transmit. The SDK encrypts your prompt in the browser or in your server process before it sends anything.
+
+* **`RescueCipher`**: Arcium's field-element symmetric cipher. Arcium chose it for compatibility with MPC, FHE, and ZK computation, so the same encrypted payload can be processed under any of those paradigms as Arcium's network matures.
+* **`X25519` key exchange**: your SDK session generates an ephemeral (single-use, per-session) X25519 keypair. The SDK derives the shared secret from your ephemeral private key and the TEE public key. The SDK fetches that key from `GET /tee/public-key`. It does not fetch or verify the attestation quote. Verification is a manual step; see [Attestation](/docs/how-it-works/attestation).
+* **TEE-generated keypair**: the TEE's own X25519 keypair is generated inside the Confidential VM at boot time. The private key never leaves the enclave, not even to Solrouter's own infrastructure.
+
+### Inference isolation
+
+Your data has to be decrypted somewhere to run the model. The question is *where*, and who can see it. With Solrouter, decryption happens inside an attested enclave. The model runs on a Nosana GPU node that the enclave calls.
+
+* **Intel TDX Confidential VM**: a hardware-enforced TEE. Memory is encrypted by the CPU and inaccessible to the host OS, hypervisor, and any Solrouter process running outside the enclave.
+* **Where plaintext exists**: the enclave decrypts your prompt, then calls the model on a Nosana GPU node (HTTPS per the documented node URL, not re-verified). The prompt and reply exist in plaintext in that node's memory during inference. The node runs outside the TDX enclave. The node operator could read the prompt at that moment; Solrouter does not control that hardware. The request is not linked to your identity on the node. When the reply returns to the enclave, it is encrypted with your session's ephemeral key before it leaves.
+* **No backend access**: no Solrouter employee, server process, or privileged operator on the backend can read your prompt or response. The hardware enforces this.
+
+### Transport
+
+Encryption only helps if there is no gap where plaintext leaks in transit between you and the enclave. There is none.
+
+* Your prompt and the reply are encrypted end-to-end between your client and the enclave. The request metadata (API key, model id, `chatId`, and any `systemPrompt`) reaches the backend in plaintext.
+* The Solrouter backend is a **blind relay**. It forwards encrypted blobs without being able to decrypt them. It never has the keys.
+
+The full request path, hop by hop, is on [How It Works](/docs/how-it-works/request-flow).
+
+## Why RescueCipher?
+
+You might wonder why Solrouter does not use a familiar cipher like AES. The answer is about where your data can go next.
+
+Most symmetric ciphers (AES-GCM, ChaCha20) are designed for classical computation. They are efficient on CPUs and GPUs but are not naturally compatible with the algebraic structures that MPC, FHE, and ZK proofs operate over.
+
+RescueCipher is a **field-element cipher**. It operates natively over the same finite-field arithmetic that MPC, FHE, and ZK systems use. That gives you three things:
+
+* The same encrypted payload you send today can, in principle, be processed directly under MPC or FHE computation without re-encryption.
+* As Arcium's MXE (Multiparty eXecution Environment) network ships support for more cryptographic compute primitives, Solrouter's encryption layer does not need to change.
+* You get a smooth upgrade path: stronger cryptographic compute guarantees over time, zero migration work on your side.
+
+This is why Arcium chose RescueCipher as the cipher for its MXE substrate, and why Solrouter uses it today, even before full MPC/FHE inference is live.
+
+## What encryption does NOT cover (yet)
+
+Privacy claims in this space are often inflated, so here is the honest line on what Solrouter does and does not do today.
+
+
+ Solrouter is **not** running pure FHE (Fully Homomorphic Encryption) inference today, and no production system does. LLM-scale FHE inference is many orders of magnitude away from viable latency. Anyone claiming "FHE LLM inference" in production is overclaiming.
+
+ What Solrouter offers today is **client-side encryption + hardware TEE isolation for decryption**, which is a real and meaningful guarantee. Arcium's MXE is a hybrid of MPC + FHE + ZK primitives, and RescueCipher is designed to work with all three. As Arcium's network matures, more of the inference pipeline will move from TEE-isolated plaintext into cryptographic compute: MPC first, then FHE/ZK where they are practical. The client encryption layer stays unchanged throughout.
+
+
+To be precise about what is and is not guaranteed today:
+
+| Property | Today |
+| ------------------------------------------ | -------------------------------------------------------------- |
+| Client-side encryption before transmission | Live: RescueCipher + X25519 |
+| Plaintext hidden from Solrouter backend | Live: decryption happens only inside the Intel TDX enclave |
+| Plaintext hidden from the Nosana GPU node | No: the model runs on plaintext on that node during inference |
+| Intel-signed TDX quote you can fetch | Live: `GET /tee/attestation` |
+| Published reference measurements | Soon: the repository is private, no reference values yet |
+| MPC-based inference | Soon: Arcium MXE roadmap |
+| Full FHE inference | Not in production anywhere today |
+
+## Encryption options in the SDK
+
+Encryption is on by default in `@solrouter/sdk`. You do not have to do anything to get it. You can turn it off for a plaintext path, but you give up every privacy guarantee on this page when you do. The plaintext path sends your prompt to the same self-hosted Nosana models. It does not unlock any other model.
+
+
+
+ ```typescript
+ // Default: fully encrypted (recommended)
+ const response = await client.chat('Your prompt', { encrypted: true });
+ ```
+
+
+ ```typescript
+ // Plaintext path: no encryption guarantees
+ const response = await client.chat('Your prompt', { encrypted: false });
+ ```
+
+
+
+
+ When you set `encrypted: false`, your prompt and response travel in plaintext through Solrouter's infrastructure. Use the plaintext path only for non-sensitive workloads.
+
diff --git a/content/docs/how-it-works/index.mdx b/content/docs/how-it-works/index.mdx
new file mode 100644
index 0000000..70b42f3
--- /dev/null
+++ b/content/docs/how-it-works/index.mdx
@@ -0,0 +1,42 @@
+---
+title: "Architecture"
+icon: Layers
+description: "Every part of Solrouter on one interactive map: what each part holds, what it can see, and where the code lives."
+status: mixed
+checked: "2026-08-26"
+statusNote: "Private swaps are Soon. Every other part of the map is Live."
+---
+
+import { Cards, Card } from 'fumadocs-ui/components/card';
+import { ArchitectureMap } from '@/components/diagrams/architecture-map';
+
+Solrouter has a handful of moving parts. This map shows all of them at once: what each part holds, what it can see, and where the code lives. Each page in this section zooms into one piece. It gets technical, and every claim points at the code.
+
+Click a node to open its details. Drag to pan. Pinch to zoom.
+
+
+
+**In words**
+
+- Chat app (solrouter.com/chat): holds your wallet session and, in Maximum Privacy Mode, encrypts each prompt in the browser. In the default mode it sends plaintext to the backend.
+- `@solrouter/sdk`: holds your API key and encrypts by default. Sends the ciphertext bundle plus the API key, model id, and chat id in plaintext.
+- `@solrouter/mcp-server` (your machine): holds `SOLROUTER_API_KEY`, `SOLROUTER_API_URL`, and `BRAVE_API_KEY`. Four tools use the encrypted path for the model step. Search and market lookups go to third parties in plaintext.
+- REST and x402 clients: send whatever they build. `POST /api/v1/chat/completions` and `/tee/process` require `encryptedPrompt`; `/agent` accepts plaintext or `encryptedPrompt`.
+- Solrouter backend (behind api.solrouter.com): checks the key, bills, runs the x402 paywall, relays ciphertext to the enclave, and commits receipts with its deployer wallet. It holds no decryption key on the encrypted path.
+- Intel TDX enclave on Phala dStack: generates an X25519 sealing key and an ed25519 signing key at boot, decrypts with RescueCipher, requests TDX quotes from the tappd agent, runs a 5-tool allowlist for encrypted agent mode, and hosts SearXNG in the same enclave.
+- Nosana GPU node, one per model: runs the open-weight model in Ollama and sees the prompt and reply during inference. Solrouter does not control that hardware.
+- Solana: holds one Light Protocol compressed receipt per private inference, under program `ATMRatMtsKX4bHax7U4FRdhbE4mjU4NKpDZGqZqAhBKb`.
+- Umbra mixer plus Jupiter (Soon): the private-swap path. The backend orchestrates it; no mainnet run is confirmed.
+- x402 facilitator: the live manifest advertises Coinbase. Which facilitator settles a payment is set on the server and is not visible from outside. The agent never talks to the facilitator.
+
+## Zoom in
+
+
+
+
+
+
+
+
+
+
diff --git a/content/docs/how-it-works/meta.json b/content/docs/how-it-works/meta.json
new file mode 100644
index 0000000..5ad913b
--- /dev/null
+++ b/content/docs/how-it-works/meta.json
@@ -0,0 +1,14 @@
+{
+ "title": "How it works",
+ "icon": "Layers",
+ "pages": [
+ "index",
+ "what-is-a-tee",
+ "request-flow",
+ "encryption",
+ "attestation",
+ "proof",
+ "agent-reasoning",
+ "models"
+ ]
+}
diff --git a/content/docs/how-it-works/models.mdx b/content/docs/how-it-works/models.mdx
new file mode 100644
index 0000000..05ddd75
--- /dev/null
+++ b/content/docs/how-it-works/models.mdx
@@ -0,0 +1,75 @@
+---
+title: "Models"
+icon: Layers
+description: "Solrouter runs only self-hosted open-weight models on Nosana GPU nodes. No prompt reaches OpenAI, Anthropic, or any other proprietary model API."
+status: mixed
+checked: "2026-08-26"
+statusNote: "The model table carries a Status column: gemma4:31b is Soon and qwen3:8b is Archived."
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+
+In privacy mode Solrouter answers with self-hosted, open-weight models only. It never calls a proprietary API. That choice is what makes the privacy claim hold.
+
+Every model runs on its own [Nosana](https://nosana.io) GPU node. Your encrypted request travels from your device to an Intel TDX enclave (a TEE, a trusted execution environment: a hardware-isolated virtual machine). The enclave decrypts it and calls the model on the Nosana node (HTTPS per the documented node URL, not re-verified). No proprietary model API is in this path.
+
+## Available models
+
+Each row is one model with its ids and its status on 2026-08-26.
+
+| Model | Catalog id | SDK id | Status |
+| --- | --- | --- | --- |
+| GPT-OSS 20B | `gpt-oss:20b` | `gpt-oss-20b` | Live |
+| Qwen 3.8 27B | `qwen3.8:27b` | none yet | Live |
+| Gemma 4 31B | `gemma4:31b` | none | Soon |
+| Qwen 3 8B | `qwen3:8b` | `qwen3-8b` | Archived |
+
+`gpt-oss:20b`: default in the chat app and the SDK. Context 8192 tokens.
+
+`qwen3.8:27b`: listed as "Uncensored" in the chat picker. In SDK 1.1.0 it needs a type cast (see below).
+
+`gemma4:31b`: listed by `GET /api/v1/models` with a 262144-token context. The enclave has no endpoint for it yet, so the encrypted path is not confirmed.
+
+`qwen3:8b`: retired node. The chat app folds this id to `qwen3.8:27b`.
+
+The REST API returns catalog ids with a `nosana:` prefix, for example `nosana:gpt-oss:20b`. The backend accepts both forms.
+
+All of these models are open-weight. Their weights are public, so anyone can inspect what runs on your prompt.
+
+## Choosing a model
+
+Leave the model out and the SDK defaults to `gpt-oss-20b`. To pick one, pass `model` to `client.chat()`:
+
+```typescript
+const response = await client.chat('Your prompt here', {
+ model: 'gpt-oss-20b', // the only typed live model in SDK 1.1.0
+});
+```
+
+The SDK type lists `gpt-oss-20b` and `qwen3-8b`. The second maps to the retired `qwen3:8b` node, so do not use it. Any other string passes through unchanged, so `nosana:qwen3.8:27b` works with a type cast. A typed alias needs a new SDK release (Soon). The chat app lets you pick `qwen3.8:27b` today.
+
+
+ Call `list_models` on the MCP server to see the models `GET /api/v1/models` returns, with the price per million tokens. Today that list holds `gpt-oss:20b` and `gemma4:31b`, so it differs from the chat picker.
+
+
+## Node warm-up
+
+A Nosana node goes idle when nobody uses it. The first request after idle time can fail with the error "Nosana GPU node is warming up". The error is retryable. Wait a short time and send the request again.
+
+## Why self-hosted models?
+
+End-to-end privacy only holds if your prompt never reaches a proprietary API. If Solrouter handed your decrypted prompt to OpenAI or Anthropic, that provider would see your plaintext. Client-side encryption and TEE isolation would then buy you nothing.
+
+Running only open-weight models on Nosana nodes closes that gap. It means:
+
+* No proprietary model provider ever sees your query, your documents, or your reply.
+* Solrouter's backend never sees your plaintext. It relays ciphertext only.
+* The model weights are public, so anyone can inspect what runs on your prompt.
+
+## Where plaintext exists
+
+The enclave decrypts your prompt and then calls the model on a Nosana GPU node (HTTPS per the documented node URL, not re-verified) with `POST /v1/chat/completions` on that node. The node runs Ollama outside the TDX enclave. So your prompt and the reply exist in plaintext in that node's memory during inference. The node operator could read the prompt during inference. Solrouter does not control that hardware. What holds: Solrouter's backend never sees plaintext, and the request is not linked to your identity on the node.
+
+
+ There are no proprietary model APIs in the Solrouter privacy pipeline: no OpenAI, no Anthropic, no Google. `{ encrypted: false }` does not unlock one. It sends your prompt in plaintext to the same self-hosted Nosana models, without TEE isolation. The SDK cannot reach any proprietary model.
+
diff --git a/content/docs/how-it-works/proof.mdx b/content/docs/how-it-works/proof.mdx
new file mode 100644
index 0000000..5da31c0
--- /dev/null
+++ b/content/docs/how-it-works/proof.mdx
@@ -0,0 +1,52 @@
+---
+title: "On-chain proof"
+icon: Stamp
+description: "Each private inference writes a receipt to Solana, signed inside the enclave. This page explains what the receipt stores and why the backend cannot forge it."
+status: live
+checked: "2026-08-26"
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+
+[Attestation](/docs/how-it-works/attestation) proves the enclave is genuine. The **encryption proof** ties *your specific request* to that enclave. Inside the enclave, a key that exists nowhere else signs the hash of your exact ciphertext, and the receipt goes to Solana. The backend relays it and cannot change it without breaking the signature.
+
+Each receipt is a **Light Protocol compressed account**: about 0.000005 SOL each, roughly 400 times cheaper than a normal Solana PDA. That cost gap is why a proof per message is viable.
+
+## What the record stores
+
+A v2 attestation lives under the Solrouter program `ATMRatMtsKX4bHax7U4FRdhbE4mjU4NKpDZGqZqAhBKb`. Its address is deterministic: `deriveAddressV2(["attestation_v2", sha256(ciphertext)])`, so a bare ciphertext hash is enough to find it. Alongside `model`, `provider`, `timestamp`, `backend_saw_plaintext`, and `tee_processed`, it stores the proof:
+
+| Field | Meaning |
+| --- | --- |
+| `client_pubkey` | Your ephemeral X25519 key from the request |
+| `tee_pubkey` | The enclave's X25519 sealing key your ciphertext was sealed to |
+| `nonce` | The RescueCipher nonce |
+| `enclave_pubkey` | The enclave's ed25519 signing key, bound inside the per-request TDX quote |
+| `enclave_sig_r` / `enclave_sig_s` | The two halves of the ed25519 signature |
+| `tdx_quote_hash` | `sha256` of the TDX quote that attests `enclave_pubkey` |
+
+Inside the enclave, the signature covers this exact byte tuple:
+
+```
+"SOLR-ATTEST-v2"
+ ‖ sha256(ciphertext) // 32 your encrypted prompt
+ ‖ tee_pubkey // 32 the sealing key
+ ‖ nonce // 16
+ ‖ client_pubkey // 32 your request key
+ ‖ len(model) ‖ model
+ ‖ len(provider) ‖ provider
+```
+
+A `POST /tee/process` reply returns this record under `onchainAttestation` (`address`, `signature`, `explorerUrl`), or `null` if the commit failed. The SDK exposes `privacyAttestationId` only; call the REST route for the full object.
+
+## Why a forged receipt is detectable
+
+The ed25519 signing key is generated inside the enclave at boot and never leaves it. The backend pays for the Solana transaction with its deployer wallet, so it could commit a record carrying any key and signature. The on-chain program stores those fields without checking them. The safeguard is the per-request TDX quote: its `report_data` equals `sha256(tee_pubkey ‖ enclave_pubkey)`, so `enclave_pubkey` is pinned to attested hardware. A verifier who checks that binding can tell a real enclave key from a forged one.
+
+
+ A passing signature check proves the key in the record signed your exact ciphertext, and that the record is on-chain. The per-request quote check proves that key belongs to an attested TDX enclave. The deepest level, Intel's full DCAP chain on the raw quote, needs the live quote from `GET /tee/attestation`.
+
+
+## Check one yourself
+
+Paste a lock link, address, transaction, or ciphertext hash into the verifier on [Check a reply yourself](/docs/verify), or read a receipt directly through the [proof-lookup endpoints](/docs/how-it-works/attestation#on-chain-attestation-anchor).
diff --git a/content/docs/how-it-works/request-flow.mdx b/content/docs/how-it-works/request-flow.mdx
new file mode 100644
index 0000000..7f769ce
--- /dev/null
+++ b/content/docs/how-it-works/request-flow.mdx
@@ -0,0 +1,42 @@
+---
+title: "The TEE request flow"
+icon: Workflow
+description: "What happens to one encrypted request, hop by hop, with the exact payload at each step."
+status: live
+checked: "2026-08-26"
+---
+
+import { RequestFlowStepper } from '@/components/diagrams/request-flow-stepper';
+import { EncryptionFlow } from '@/components/diagrams/encryption-flow';
+
+This page follows one `client.chat()` call through the SDK, the Solrouter backend, the Intel TDX enclave, the Nosana GPU node, and back. Use the step list to walk the map. Each step names its payload and source file.
+
+
+
+**In words**
+
+1. `GET /tee/public-key` returns `{publicKey, publicKeySha256, algorithm, teeType}`. The SDK caches it for the life of the process.
+2. The SDK makes an ephemeral X25519 keypair and derives the shared secret with the enclave key.
+3. RescueCipher encrypts the prompt in packed-31 form. The bundle is `{ciphertext, nonce, publicKey, version: '2.0-packed31'}`.
+4. `POST /tee/process` with a Bearer key. What leaves the machine: the ciphertext bundle plus, in plaintext, the API key, model id, `chatId`, and the optional `systemPrompt`, `useRAG`, `ragCollection`, `useLiveSearch`.
+5. The backend forwards `{encryptedPrompt, model, privacyAttestationId}` unchanged.
+6. The CVM derives the shared secret with its X25519 private key and decrypts.
+7. The CVM calls the configured Nosana endpoint at `/v1/chat/completions` with the plaintext prompt. HTTPS per the documented node URL, not re-verified.
+8. The CVM encrypts the reply to your key, signs the `SOLR-ATTEST-v2` tuple, and requests a tappd quote with `report_data = sha256(x25519 || ed25519)`.
+9. The backend commits the compressed receipt and returns `{success, encryptedResponse, attestation, encryptionProof, requestId, metadata, backendRole: 'BLIND_RELAY', onchainAttestation, privacyProof}`.
+10. The SDK decrypts `encryptedResponse` with the session private key.
+
+## The short picture
+
+
+
+**In words**
+
+- Your device encrypts. The backend relays ciphertext. The enclave decrypts. The Nosana node runs the model in plaintext. The reply returns encrypted.
+
+## Key custody
+
+- Your device: an ephemeral X25519 private key per session. Never sent.
+- Solrouter backend: no key on this path.
+- Enclave: an X25519 sealing key and an ed25519 signing key, generated at boot and never exported.
+- Nosana node: no key. It receives plaintext from the enclave.
diff --git a/content/docs/how-it-works/what-is-a-tee.mdx b/content/docs/how-it-works/what-is-a-tee.mdx
new file mode 100644
index 0000000..d1f7f63
--- /dev/null
+++ b/content/docs/how-it-works/what-is-a-tee.mdx
@@ -0,0 +1,81 @@
+---
+title: "What is a TEE?"
+icon: ShieldCheck
+description: "A TEE is a sealed part of a computer that the cloud operator cannot look into, and this page explains what that means for your prompt."
+status: live
+checked: "2026-08-26"
+statusNote: "Describes the Intel TDX enclave on Phala Cloud that answers at api.solrouter.com/tee/public-key today."
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+import { Card, Cards } from 'fumadocs-ui/components/card';
+import { SealedRoom } from '@/components/diagrams/sealed-room';
+
+## The question
+
+You type a prompt. A computer somewhere works on it. Who can read the prompt while that happens?
+
+With a normal AI service, the answer is "the company that runs the server". Their staff can read it. Their logs can store it. A TEE changes that answer for one part of the path.
+
+TEE is short for Trusted Execution Environment. In plain words: a sealed part of a computer. The program inside can work on your data. The people who own the computer cannot look in. See the [glossary](/docs/glossary) for the short form of every term on this page.
+
+## The sealed room
+
+
+
+**In words**
+
+- A data center holds many computers. One of them runs Solrouter's private inference program.
+- That program lives in a sealed room called a Confidential VM. A VM is a virtual machine: one computer pretending to be a separate, smaller computer.
+- The room has one locked slot. Only data sealed to the room's public key can go in. Your device seals your prompt to that key before it leaves your machine.
+- The room has one window. Through it, anyone can read a signed note that says which program is running inside. That note is the attestation.
+- The operator of the data center stands outside. The CPU encrypts everything in the room's memory, so the operator cannot open the door.
+
+Where the analogy breaks: a real sealed room keeps everything inside. A TEE does not. The program inside can still send data out to other computers. The next sections say where Solrouter's program does that.
+
+## Two layers
+
+A TEE gives you two separate promises.
+
+### Layer 1: isolation
+
+The CPU chip encrypts the memory of the Confidential VM. The cloud operator, the host operating system, and any other program on the same machine see only scrambled bytes. This is why Solrouter can say its own backend and its cloud host never see your prompt in plain text.
+
+### Layer 2: attestation
+
+A sealed room could still hold the wrong program, one that copies your prompt somewhere. Attestation closes that gap.
+
+The chip signs a short note. The note says: "This exact program is running in this room right now." Anyone can fetch the note and check the signature against Intel's public records. Solrouter also puts a fingerprint of the room's public key inside the note. When you check the note, you also confirm the key belongs to this room. An impostor cannot fake that.
+
+Think of a tamper-evident seal on a package. The seal shows the package was not opened. It does not tell you what is inside. Attestation proves which program runs. It does not by itself prove the program is a good one. For that you need to compare the note against known reference values. Solrouter does not publish those values yet. Reference measurements: Soon.
+
+## What a TEE does not do
+
+A TEE stops outsiders from looking in. It does not stop the program inside from talking out.
+
+Solrouter's program inside the enclave decrypts your prompt. It then sends the plain-text prompt to a Nosana GPU node, a separate computer that runs the language model. That node is outside the sealed room. The node can see your prompt and the reply during inference. Solrouter does not control that hardware. The request is not linked to your identity on the node.
+
+Solrouter's own deployment file states the same limit. It claims "Solrouter never sees your prompt or searches" and adds "NOT no one sees them".
+
+
+Solrouter's backend and its cloud host cannot read your prompt. The Nosana GPU node that runs the model can, while it works on it.
+
+
+The page [What is private here](/docs/use/what-is-private) has the full table of who can see what.
+
+## How Solrouter uses one
+
+Solrouter runs its enclave as an Intel TDX Confidential VM on Phala Cloud. TDX is Intel's name for this kind of sealed VM. Phala Cloud is the hosting service that provides the TDX machines.
+
+When the enclave boots, it makes a fresh key pair inside the sealed room. The private half never leaves. The public half is published at `GET https://api.solrouter.com/tee/public-key`. That reply names the enclave type as `INTEL-TDX-PHALA`. The key changes on every reboot, so a copied key from last week is useless.
+
+The signed note comes from `GET https://api.solrouter.com/tee/attestation`. Solrouter's program asks the Phala guest agent inside the same Confidential VM for it, then passes it to you unchanged.
+
+## Check it yourself
+
+You do not have to take Solrouter's word for any of this.
+
+
+
+
+
diff --git a/content/docs/index.mdx b/content/docs/index.mdx
index 2a19c54..8ef65aa 100644
--- a/content/docs/index.mdx
+++ b/content/docs/index.mdx
@@ -1,117 +1,45 @@
---
title: "Introduction"
icon: Sparkles
-description: Solrouter is a cryptographically private AI layer — prompts are encrypted client-side and processed in an Intel TDX enclave, so no one can read your data.
+description: "Solrouter is a private AI layer for Solana. Your prompt is encrypted on your device, and the Solrouter backend never sees it in plaintext."
+status: live
+checked: "2026-08-26"
---
import { Cards, Card } from 'fumadocs-ui/components/card';
import { Callout } from 'fumadocs-ui/components/callout';
-import {
- Shield,
- Bot,
- Plug,
- MessageSquare,
- Lock,
- Cpu,
- BadgeCheck,
- UserX,
- Box,
- Link2,
-} from 'lucide-react';
+import { TypicalVsSolrouter } from '@/components/diagrams/typical-vs-solrouter';
+import { MessageSquare, Code, Layers, ShieldCheck } from 'lucide-react';
-Solrouter is a cryptographically private AI infrastructure layer for Solana
-developers. The idea is simple: your prompts, documents, and responses should
-never exist in plaintext anywhere we could read them. So they don't — not on the
-wire, not on our backend, and not in any log file. Plaintext lives only inside a
-hardware-isolated enclave. Privacy here is enforced by math, not by a promise.
+Solrouter is a private AI layer for Solana. On the encrypted path, your prompt is encrypted on your device, stays encrypted through the Solrouter backend, and is decrypted only inside a hardware-isolated enclave. The backend never sees it in plaintext.
-## Why Solrouter?
+
-Start with the problem. Today, every AI request you send is something the
-provider can read, store, and analyze.
+**In words**
-Mainstream providers keep your prompts indefinitely, ask for personal details to
-sign up, and back their privacy claims with a terms-of-service page. Nothing
-technical stops them from reading what you send — you're trusting a policy.
-
-Solrouter removes the need for that trust. We built the system so that **we
-cannot see your data** in the first place.
-
-Here's how. Your prompt is encrypted on your device before it leaves your browser
-or app. Our backend only ever receives an opaque encrypted blob and forwards it,
-blindly, to an Intel TDX Confidential VM — a TEE (Trusted Execution Environment:
-hardware that isolates code and data so even the machine's operator can't inspect
-it at runtime). Plaintext appears only inside that attested enclave, which even
-we cannot read.
+- A typical AI API reads your prompt as plain text on its own server.
+- With Solrouter, your device encrypts the prompt first. The backend relays ciphertext and never sees the words.
+- Only the enclave holds the key. It runs the model on a Nosana GPU node, then encrypts the reply so only your device can read it.
- In privacy mode, Solrouter does not use OpenAI, Anthropic, Google, or any
- third-party model provider. All private inference runs on self-hosted,
- open-weight models on the Nosana decentralized GPU network. Your prompts never
- reach an external model API.
+ Private inference runs only on self-hosted, open-weight models on the Nosana GPU network. Solrouter does not send your prompt to OpenAI, Anthropic, or Google. The Nosana node that runs the model sees the prompt during inference, and Solrouter does not control that hardware.
-## Products
-
-Pick the surface that fits how you work — an SDK to embed in your app, typed
-agent tools, an MCP server for your editor, or the hosted chat app. They all run
-on the same private backend.
+## Choose your surface
- } title="Privacy SDK" href="/docs/develop/privacy-sdk">
- **`@solrouter/sdk`** — integrate end-to-end encrypted AI into your app. The
- SDK handles key exchange, client-side encryption with Arcium RescueCipher,
- and response decryption for you. No email or KYC — connect a Solana wallet
- and start building.
+ } title="Use the chat app" href="/docs/use/chat-app">
+ Chat in the browser. No code. Turn on Maximum Privacy Mode to encrypt each prompt.
- } title="Agent Tools SDK" href="/docs/develop/agent-tools-sdk">
- **`@solrouter/agent-tools`** — typed tools for the Agent Privacy API with a
- Vercel AI SDK adapter. Quote, execute, and settle privacy-preserving swaps
- and encrypted inference without writing orchestration boilerplate.
+ } title="Build on the API" href="/docs/build/quickstart">
+ Add encrypted AI to your app or agent with the SDK, the MCP server, or the REST API.
- } title="MCP Server" href="/docs/develop/mcp-server">
- **`@solrouter/mcp-server`** — use Solrouter from Claude Desktop, Cursor, or
- any MCP-compatible client. Encrypted chat, private token research, and wallet
- analysis without writing any code.
+ } title="See how it works" href="/docs/how-it-works">
+ The enclave, encryption, attestation, and the on-chain proof, each with the code.
- } title="Chat App" href="https://solrouter.com/chat">
- Multi-model encrypted chat with file attachments, image and video
- generation, and a RAG knowledge base. No account needed beyond a connected
- Solana wallet.
+ } title="Check a reply yourself" href="/docs/verify">
+ Paste a lock link and watch the verification pass in your browser.
-## Key Guarantees
-
-These are the promises that hold for any privacy-mode request, no matter which
-product you reach for. Each one is a property the system enforces, not a feature
-you have to remember to turn on.
-
-
- } title="Client-Side Encryption">
- Your prompt is encrypted on your own device — using Arcium's RescueCipher
- with X25519 key exchange — before it leaves your browser or application.
-
- } title="TEE-Isolated Inference">
- Plaintext exists only inside an Intel TDX Confidential VM. No host process —
- including Solrouter's own backend — can read enclave memory at runtime.
-
- } title="Verifiable Attestation">
- Don't take our word for it. Every TEE response carries an Intel-signed TDX
- quote, so you can independently verify the enclave's public key and the exact
- code running inside it.
-
- } title="No KYC or Email Required">
- Connect a Solana wallet, generate an API key, and start building. You pay per
- call in USDC or `$ROUTER` from a prepaid balance — no signup form, no PII.
-
- } title="Open-Weight Models Only">
- All privacy-mode inference runs on self-hosted open-weight models
- (`gpt-oss:20b` and `qwen3:8b`) on the Nosana decentralized GPU network.
-
- } title="On-Chain Attestation Anchor">
- The Solrouter attestation program is deployed on Solana mainnet. Each
- privacy-mode session can publish a PDA that links the request to the verified
- enclave on-chain.
-
-
+New to the tech? Start with [What is a TEE?](/docs/how-it-works/what-is-a-tee) and [What is private here](/docs/use/what-is-private).
diff --git a/content/docs/meta.json b/content/docs/meta.json
index 7d0ce3f..2dc9a03 100644
--- a/content/docs/meta.json
+++ b/content/docs/meta.json
@@ -1,12 +1,14 @@
{
"pages": [
- "---Get Started---",
"index",
- "quickstart",
- "chat-app",
- "concepts",
- "develop",
- "payments",
- "api-reference"
+ "use-cases",
+ "verify",
+ "use",
+ "build",
+ "how-it-works",
+ "---Reference---",
+ "api-reference",
+ "glossary",
+ "token"
]
}
diff --git a/content/docs/payments/meta.json b/content/docs/payments/meta.json
deleted file mode 100644
index fa2fedf..0000000
--- a/content/docs/payments/meta.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "title": "Payments",
- "icon": "Coins",
- "pages": ["overview", "tokenomics"]
-}
diff --git a/content/docs/payments/overview.mdx b/content/docs/payments/overview.mdx
deleted file mode 100644
index 8e5f677..0000000
--- a/content/docs/payments/overview.mdx
+++ /dev/null
@@ -1,65 +0,0 @@
----
-title: "Pricing"
-icon: CircleDollarSign
-description: "Solrouter is metered per API call. Prepay in USDC or $ROUTER from your Solana wallet — no subscription, no credit card, no email required."
----
-
-import { Cards, Card } from 'fumadocs-ui/components/card';
-import { Callout } from 'fumadocs-ui/components/callout';
-import { CircleDollarSign, RotateCw } from 'lucide-react';
-
-Most AI platforms make you commit before you build: a monthly subscription, a credit card on file, an email to verify. Solrouter does none of that. You pay per API call from a balance you fund yourself, so you only ever spend what you use.
-
-The setup is short. Connect a Solana wallet at [solrouter.com/sdk](https://solrouter.com/sdk), fund your balance with USDC or `$ROUTER`, generate an API key, and start building. Every product — the Privacy SDK, Agent Privacy API, MCP server, and chat app — draws from that same prepaid balance.
-
-
- There are no hidden fees. You pay per call from your prepaid balance. When the balance reaches zero, calls stop — nothing is billed retroactively.
-
-
-## Payment methods
-
-You can fund your balance two ways. Both cost the same per call; the difference is what each one means for you and for the token.
-
-
- }>
- Pay with USDC from your Solana wallet. As a stablecoin pegged to the dollar, its value stays put — so you carry no price risk between top-ups. Top up at any time from [solrouter.com/sdk](https://solrouter.com/sdk).
-
-
- }>
- Pay with the native `$ROUTER` token at the same per-call price as USDC. Every fee you pay in `$ROUTER` feeds the buyback-and-burn model — see [\$ROUTER buyback and burn](#router-buyback-and-burn) below.
-
-
-
-## x402 keyless payments
-
-An autonomous agent often has no human around to sign up for an account or manage an API key. x402 solves that: it lets an agent pay for each call on its own, with no registration at all.
-
-x402 is a standard for HTTP-native micropayments — payments built directly into the web request itself — settled in USDC on Solana mainnet and facilitated by Coinbase. Any x402-aware agent can discover the payment manifest and start paying immediately.
-
-* **Discovery:** `/.well-known/x402` — the x402 paywall manifest listing available endpoints and pricing.
-* **Endpoint:** `POST /api/v1/x402/chat/completions` — Arcium-encrypted prompt in, encrypted response out.
-* **Price:** \$0.005 per call, settled on-chain before the request is processed.
-* **Best for:** autonomous agents that self-fund their own inference costs without a human managing API keys.
-
-Going keyless costs you no privacy. The x402 path runs the same end-to-end encrypted inference as the API-key path: your prompt is still encrypted with RescueCipher before it reaches Solrouter's backend.
-
-## Managing your balance
-
-You can read your current balance straight from the SDK, so an agent or app can check funds before it spends and top up when it runs low.
-
-```typescript
-const { balance, balanceFormatted } = await client.getBalance();
-console.log(`Balance: ${balanceFormatted}`);
-```
-
-To add funds, visit [solrouter.com/sdk](https://solrouter.com/sdk) and connect your Solana wallet. Deposit USDC or `$ROUTER` in any amount — there is no minimum.
-
-## \$ROUTER buyback and burn
-
-Here is what your fees do for the token. The model is deliberately simple and mechanical: no emissions, no staking curves, no tiered discount programs — just supply that tightens as the network is used.
-
-* **100% of USDC revenue** flows into buying back `$ROUTER` on the open market.
-* **50% of each buyback** is permanently burned, reducing total supply.
-* **50% of `$ROUTER` fees** paid directly are burned at the time of payment.
-
-Every call you make — whether you pay in USDC or `$ROUTER` — tightens supply. See [/docs/payments/tokenomics](/docs/payments/tokenomics) for the full token mechanics, supply schedule, and vesting details.
diff --git a/content/docs/quickstart.mdx b/content/docs/quickstart.mdx
deleted file mode 100644
index 955d73b..0000000
--- a/content/docs/quickstart.mdx
+++ /dev/null
@@ -1,118 +0,0 @@
----
-title: "Quickstart"
-icon: Rocket
-description: "Install @solrouter/sdk, generate an API key with your Solana wallet, and send your first encrypted AI request with just a few lines of TypeScript."
----
-
-import { Cards, Card } from 'fumadocs-ui/components/card';
-import { Callout } from 'fumadocs-ui/components/callout';
-import { Step, Steps } from 'fumadocs-ui/components/steps';
-import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
-import { Lock, KeyRound, Bot, Code } from 'lucide-react';
-
-Most AI APIs can read every prompt you send them. Solrouter doesn't: your message is encrypted on your machine before it leaves, and the backend relays it without ever seeing the plaintext. In the next five steps you'll set that up end to end — sign in with a Solana wallet, install the SDK, and send your first encrypted request. No email, no credit card, just a wallet and a few lines of TypeScript.
-
-
-
- ### Get an API key
-
- Your key is how Solrouter authenticates you and bills your usage — and it's tied to your wallet, not your identity.
-
- Go to [solrouter.com/sdk](https://solrouter.com/sdk), connect your Solana wallet, and generate an API key. Top up your prepaid balance in USDC or \$ROUTER to start making calls.
-
-
- No email, no credit card, and no KYC required. Your API key is tied to your wallet — that's it.
-
-
-
-
- ### Install the SDK
-
- The SDK handles encryption, routing, and decryption for you, so you write normal TypeScript and get privacy by default.
-
- Add `@solrouter/sdk` to your project using your preferred package manager.
-
-
-
- ```bash
- npm install @solrouter/sdk
- ```
-
-
- ```bash
- yarn add @solrouter/sdk
- ```
-
-
- ```bash
- pnpm add @solrouter/sdk
- ```
-
-
-
-
-
- ### Initialize the client
-
- One line gets you a configured client. Pass your API key and you're ready to make calls.
-
- The SDK automatically fetches the TEE's attested public key — the encryption target for your prompts (a TEE, or Trusted Execution Environment, is hardware that isolates code and data even from the machine's owner). You don't need to configure anything else.
-
- ```typescript
- import { SolRouter } from '@solrouter/sdk';
-
- const client = new SolRouter({
- apiKey: 'sk_solrouter_...'
- });
- ```
-
-
-
- ### Send your first encrypted chat
-
- This is where the privacy guarantee pays off: your prompt travels encrypted the whole way, and only the TEE can read it.
-
- Call `client.chat()` to send a message. The SDK encrypts it client-side with Arcium's RescueCipher, routes the encrypted blob through the Solrouter backend (which can't read it), and decrypts the response for you automatically.
-
- ```typescript
- // Encrypted end-to-end — Solrouter backend never sees plaintext
- const response = await client.chat('What are the risks of this DeFi protocol?');
- console.log(response.message);
- ```
-
-
-
- ### Check your balance
-
- Solrouter bills against prepaid funds, so check your remaining balance any time — for example, before a batch of calls or to surface it in your own UI.
-
- Query your prepaid balance:
-
- ```typescript
- const { balance, balanceFormatted } = await client.getBalance();
- console.log(`Balance: ${balanceFormatted}`);
- ```
-
-
-
-## Next steps
-
-You've sent an encrypted request and checked your balance — that's the core loop. Where you go next depends on what you're building: the full SDK surface, private on-chain agent actions, or direct HTTP access.
-
-
- } href="/docs/develop/privacy-sdk">
- Full `@solrouter/sdk` documentation: model selection, opt-out mode, SERV reasoning, and more.
-
-
- } href="/docs/develop/authentication">
- Learn about API key auth, x402 keyless payments, and keeping your credentials safe.
-
-
- } href="/docs/develop/agent-tools-sdk">
- Typed tools for private swaps and encrypted inference in any function-calling agent framework.
-
-
- } href="/docs/api-reference/overview">
- Browse the full REST API, including the agent endpoint and x402 paywall spec.
-
-
diff --git a/content/docs/payments/tokenomics.mdx b/content/docs/token.mdx
similarity index 52%
rename from content/docs/payments/tokenomics.mdx
rename to content/docs/token.mdx
index 0d57182..b429dc5 100644
--- a/content/docs/payments/tokenomics.mdx
+++ b/content/docs/token.mdx
@@ -1,7 +1,10 @@
---
title: "$ROUTER Token"
icon: Coins
-description: "$ROUTER is Solrouter's utility token on Solana. 1B total supply, 53.04% at TGE, with a buyback-and-burn model funded by 100% of protocol revenue."
+description: "$ROUTER is Solrouter's utility token on Solana. 1B total supply, 53.04% at TGE, with a buyback-and-burn mechanism whose ratios are not yet published."
+status: mixed
+checked: "2026-08-26"
+statusNote: "The token and its supply schedule are Live. Buyback and burn is Soon: the configured ratios are not published."
---
import { Cards, Card } from 'fumadocs-ui/components/card';
@@ -10,7 +13,7 @@ import { TokenAllocation } from '@/components/diagrams/token-allocation';
Most utility tokens bury their value behind staking lockups, emissions schedules, and governance you have to opt into. `$ROUTER` does the opposite: it is a way to pay for what you use, and nothing more.
-`$ROUTER` is Solrouter's utility token on Solana. You spend it on API calls across every Solrouter product — the Privacy SDK, Agent Privacy API, MCP server, and chat app — at the same per-call rate as USDC. There are no emissions, no staking rewards, and no governance complexity. One mechanic drives the whole design: protocol revenue buys back and burns `$ROUTER`, so supply tightens as usage grows.
+`$ROUTER` is Solrouter's utility token on Solana. You spend it on API calls across every Solrouter product (the Privacy SDK, Agent Privacy API, MCP server, and chat app). There are no emissions, no staking rewards, and no governance complexity. One mechanic drives the whole design: protocol revenue can buy back and burn `$ROUTER`, so supply tightens as usage grows.
## Token details
@@ -42,11 +45,11 @@ Here is where the 1B supply goes, and how quickly each slice becomes spendable.
## Circulating supply schedule
-Locked supply can't be sold, so this is how the float — and the potential sell pressure — grows over time.
+Locked supply cannot be sold, so this is how the float (and the potential sell pressure) grows over time.
-Tokens enter circulation over 24 months. The Liquidity Pool, OpenServ, and Superteam Germany allocations unlock at TGE (Token Generation Event — the moment the token first goes live). Treasury releases 9.5% at TGE and vests the rest linearly over 24 months.
+Tokens enter circulation over 24 months. The Liquidity Pool, OpenServ, and Superteam Germany allocations unlock at TGE (Token Generation Event, the moment the token first goes live). Treasury releases 9.5% at TGE and vests the rest linearly over 24 months.
-The Team allocation has a 3-month cliff (zero unlocks until month three), then vests linearly over the following 12 months. Algorithmic Fundraising unlocks per FDV band as each band clears, so the schedule below is indicative — the real cadence depends on demand.
+The Team allocation has a 3-month cliff (zero unlocks until month three), then vests linearly over the following 12 months. Algorithmic Fundraising unlocks per FDV band as each band clears, so the schedule below is indicative. The real cadence depends on demand.
| Milestone | Circulating % | Circulating Tokens |
| --------- | ------------- | ------------------ |
@@ -57,27 +60,27 @@ The Team allocation has a 3-month cliff (zero unlocks until month three), then v
## Algorithmic fundraising
-Instead of selling the raise allocation all at once, Solrouter releases it in steps tied to the token's own valuation — so capital comes in only as the market values the protocol higher.
-
-5% of total supply (50,000,000 `$ROUTER`) sells across 14 FDV (Fully Diluted Valuation — the value of the entire 1B supply at the current price) bands ranging from $500K to $100M. Each band unlocks only after the previous band's valuation threshold clears, raising capital progressively as demand grows. Total estimated capital across all 14 bands is roughly \$807,750, calculated using each band's midpoint valuation.
-
-| Band | Valuation (USD) | % of Supply | Capital Raised | Cumulative |
-| --------- | --------------- | ----------- | -------------- | ------------- |
-| 1 | $500K – $750K | 0.30% | \$1,875 | \$1,875 |
-| 2 | $750K – $1M | 0.30% | \$2,625 | \$4,500 |
-| 3 | $1M – $1.5M | 0.35% | \$4,375 | \$8,875 |
-| 4 | $1.5M – $2M | 0.35% | \$6,125 | \$15,000 |
-| 5 | $2M – $3M | 0.40% | \$10,000 | \$25,000 |
-| 6 | $3M – $5M | 0.40% | \$16,000 | \$41,000 |
-| 7 | $5M – $8M | 0.45% | \$29,250 | \$70,250 |
-| 8 | $8M – $12M | 0.45% | \$45,000 | \$115,250 |
-| 9 | $12M – $18M | 0.50% | \$75,000 | \$190,250 |
-| 10 | $18M – $25M | 0.50% | \$107,500 | \$297,750 |
-| 11 | $25M – $40M | 0.40% | \$130,000 | \$427,750 |
-| 12 | $40M – $60M | 0.30% | \$150,000 | \$577,750 |
-| 13 | $60M – $80M | 0.20% | \$140,000 | \$717,750 |
-| 14 | $80M – $100M | 0.10% | \$90,000 | \$807,750 |
-| **Total** | | **5.00%** | **\$807,750** | **\$807,750** |
+Instead of selling the raise allocation all at once, Solrouter releases it in steps tied to the token's own valuation. Capital comes in only as the market values the protocol higher.
+
+5% of total supply (50,000,000 `$ROUTER`) sells across 14 FDV (Fully Diluted Valuation, the value of the entire 1B supply at the current price) bands ranging from $500K to $100M. Each band unlocks only after the previous band's valuation threshold clears, raising capital progressively as demand grows. Total estimated capital across all 14 bands is roughly \$807,750, calculated using each band's midpoint valuation.
+
+| Band | Valuation (USD) | % of Supply | Capital Raised | Cumulative |
+| --------- | ---------------- | ----------- | -------------- | ------------- |
+| 1 | $500K to $750K | 0.30% | \$1,875 | \$1,875 |
+| 2 | $750K to $1M | 0.30% | \$2,625 | \$4,500 |
+| 3 | $1M to $1.5M | 0.35% | \$4,375 | \$8,875 |
+| 4 | $1.5M to $2M | 0.35% | \$6,125 | \$15,000 |
+| 5 | $2M to $3M | 0.40% | \$10,000 | \$25,000 |
+| 6 | $3M to $5M | 0.40% | \$16,000 | \$41,000 |
+| 7 | $5M to $8M | 0.45% | \$29,250 | \$70,250 |
+| 8 | $8M to $12M | 0.45% | \$45,000 | \$115,250 |
+| 9 | $12M to $18M | 0.50% | \$75,000 | \$190,250 |
+| 10 | $18M to $25M | 0.50% | \$107,500 | \$297,750 |
+| 11 | $25M to $40M | 0.40% | \$130,000 | \$427,750 |
+| 12 | $40M to $60M | 0.30% | \$150,000 | \$577,750 |
+| 13 | $60M to $80M | 0.20% | \$140,000 | \$717,750 |
+| 14 | $80M to $100M | 0.10% | \$90,000 | \$807,750 |
+| **Total** | | **5.00%** | **\$807,750** | **\$807,750** |
*Capital estimated using each band's midpoint valuation.*
@@ -89,28 +92,30 @@ For the first 130 seconds after the liquidity pool opens, per-transfer and per-w
| Time After Open | Max Per Transfer | Max Per Wallet (Buys) |
| ----------------- | ---------------- | --------------------- |
-| 0 – 70 seconds | 100,000 (0.01%) | 1,000,000 (0.1%) |
-| 70 – 130 seconds | 1,000,000 (0.1%) | 5,000,000 (0.5%) |
+| 0 to 70 seconds | 100,000 (0.01%) | 1,000,000 (0.1%) |
+| 70 to 130 seconds | 1,000,000 (0.1%) | 5,000,000 (0.5%) |
| After 130 seconds | No limit | No limit |
## Buyback and burn
-This is the engine that ties token value to real usage: the more people pay Solrouter, the more `$ROUTER` permanently leaves circulation. Revenue flows straight into supply reduction — no intermediary pools, no governance votes, no discretionary treasury spending.
+Status: Soon. This is the engine that ties token value to real usage: the more people pay Solrouter, the more `$ROUTER` can leave circulation. The mechanism exists in code. The ratios are runtime settings (`BURN_USDC_BPS`, `BURN_OUTPUT_TOKEN_BPS`, `BURN_TOKEN_BPS`), and the worker skips its run while they are zero.
- }>
- Of USDC revenue goes toward buying back `$ROUTER` on the open market.
+ }>
+ Status: Soon. A configured share of USDC revenue buys back `$ROUTER` on the open market through Jupiter.
- }>
- Of each buyback is permanently burned, permanently reducing total supply.
+ }>
+ Status: Soon. A configured share of each buyback is burned. The rest stays in treasury.
- }>
- Of `$ROUTER` fees paid directly are burned at the time of payment.
+ }>
+ Status: Soon. A configured share of `$ROUTER` fees paid directly is burned on receipt. The rest stays in treasury.
-The model stays simple on purpose. No emissions mint new tokens, no staking curves add complexity, and no tiered discount programs fragment the tokenomics. Every API call reduces supply — whether you pay in USDC or `$ROUTER`. The more Solrouter is used, the tighter the supply becomes.
+Configured ratios: not published. `GET /payments/buyback/log` returns the recent buyback worker ticks, including skipped ones.
-To pay for API calls with `$ROUTER`, see [Pricing](/docs/payments/overview).
+The model stays simple on purpose. No emissions mint new tokens, no staking curves add complexity, and no tiered discount programs fragment the tokenomics.
+
+To pay for API calls with `$ROUTER`, see [Pricing](/docs/use/pricing).
diff --git a/content/docs/use-cases.mdx b/content/docs/use-cases.mdx
new file mode 100644
index 0000000..bdfccae
--- /dev/null
+++ b/content/docs/use-cases.mdx
@@ -0,0 +1,202 @@
+---
+title: "Use cases"
+icon: Compass
+description: "What people, developers, agents, traders, and teams do with Solrouter today, and what is still on the way."
+status: mixed
+checked: "2026-08-26"
+statusNote: "Each card carries its own Status word. The Live cards for privacy modes, memory, guest mode, and team accounts depend on the owner's browser check in PR 5."
+---
+
+import { Cards, Card } from 'fumadocs-ui/components/card';
+import { Callout } from 'fumadocs-ui/components/callout';
+import {
+ FileText,
+ Code,
+ PenLine,
+ History,
+ Brain,
+ UserX,
+ Paperclip,
+ BadgeCheck,
+ Shield,
+ Plug,
+ Route,
+ Lock,
+ Wallet,
+ Coins,
+ ArrowLeftRight,
+ Repeat,
+ Globe,
+ FolderOpen,
+ Users,
+} from 'lucide-react';
+
+Every card below starts with one Status word. We checked each against the code
+on 2026-08-26. **Live** works today. **Soon** exists in code but is not switched
+on or not confirmed end to end. **Archived** was removed.
+
+Many cards mention a sealed machine. That is a TEE (Trusted Execution
+Environment). Its own operator cannot look inside while it runs.
+[What is a TEE?](/docs/how-it-works/what-is-a-tee) explains it with a picture.
+Other terms are in the [Glossary](/docs/glossary): [wallet](/docs/glossary),
+[x402](/docs/glossary), and [mixer](/docs/glossary).
+
+
+ When encryption is on, Solrouter's own servers never see your words in
+ readable form. The GPU computer that runs the AI model does see them while it
+ writes the answer. Solrouter does not own that computer. Read
+ [What is private here](/docs/use/what-is-private).
+
+
+## For people
+
+These are for anyone who uses the chat app at solrouter.com. Encryption in the
+chat app is a switch called Maximum Privacy mode. It is off when you first
+open the app. While it is on, the app keeps no history.
+
+
+ } title="Summarise a contract off the record" href="/docs/use/chat-app">
+ **Live.** You want a summary of a contract, but you do not want an AI
+ company to keep a copy. Turn on Maximum Privacy mode and paste the text,
+ because an attached file is not encrypted.
+
+ } title="Review code without sharing it" href="/docs/use/chat-app">
+ **Live.** You want feedback on code that is not public. Turn on Maximum
+ Privacy mode and paste the code, and Solrouter's servers never see it in
+ readable form.
+
+ } title="Draft a reply nobody else gets to read" href="/docs/use/chat-app">
+ **Live.** You want help with a sensitive message, such as a letter to a
+ doctor or a lawyer. Turn on Maximum Privacy mode, write the draft, and
+ close the tab, because nothing is saved.
+
+ } title="Keep your history, or keep nothing" href="/docs/use/chat-app">
+ **Live.** Some chats should survive a reload and others should leave no
+ trace. Persistent mode saves history encrypted with a key that Solrouter
+ holds, and Maximum Privacy mode saves nothing at all.
+
+ } title="Memory that only your wallet can unlock" href="/docs/use/chat-app">
+ **Live.** You want the assistant to remember facts across chats without
+ Solrouter holding a readable profile of you. Your wallet signs a fixed
+ message to make the key, so Solrouter stores only a locked blob.
+
+ } title="Try it with no wallet and no account" href="/docs/use/chat-app">
+ **Live.** You will not connect a wallet before you have seen the product
+ work. Open the guest page and send up to five free messages a day.
+
+ } title="Attach a file to a chat" href="/docs/use/chat-app">
+ **Live.** You want to ask about a PDF, a spreadsheet, or a screenshot. You
+ can attach it, but attachments are not encrypted, and documents are stored
+ in readable form on a file server.
+
+ } title="Check that a reply came from the sealed machine" href="/docs/verify">
+ **Live.** A privacy promise on a web page is not proof. Click the lock link
+ under a reply, or paste it into the checker, and see the receipt on the
+ Solana blockchain.
+
+
+
+**Archived.** Image and video generation was switched off in the chat app, and
+the services that made them were removed.
+
+## For developers
+
+These are for people who write code and want to add private AI to their own
+app, editor, or backend.
+
+
+ } title="Encrypted chat from your own app" href="/docs/build/privacy-sdk">
+ **Live.** Every mainstream AI service can read what your app sends it, so
+ you cannot promise your users privacy. Install `@solrouter/sdk`, call
+ `client.chat()`, and the prompt is encrypted on your machine before it
+ leaves.
+
+ } title="Private research inside Claude Desktop or Cursor" href="/docs/build/mcp-server">
+ **Live.** Research done through a normal assistant shows the model provider
+ which tokens and wallets you look at. Paste one config block, and only
+ the synthesis step runs encrypted; web searches and price lookups stay
+ readable.
+
+ } title="Research with fixed steps instead of a free-running agent" href="/docs/how-it-works/agent-reasoning">
+ **Live.** A normal agent asks the model what to do at every step, which is
+ slow and hard to predict. Send `reasoning: 'braid'` and the agent walks a
+ fixed diagram of steps, but on this path your prompt travels in readable
+ form.
+
+ } title="Run the whole agent loop inside the sealed machine" href="/docs/api-reference/agent">
+ **Live** over the REST endpoint, and Soon in the SDK. An agent that searches
+ the web and reads prices normally shows every question to the server. Send
+ an encrypted prompt to `POST /agent`, and the loop runs inside the sealed
+ machine with five approved tools.
+
+ } title="Pay per call with no email, card, or KYC" href="/docs/build/api-key">
+ **Live.** Signing up for an AI service means handing over your identity and
+ a card. Connect a Solana wallet, make an API key, and top up a balance in
+ USDC or $ROUTER.
+
+
+
+## For agents
+
+These are for software agents that hold a Solana wallet and act on their own,
+with no person to manage keys.
+
+
+ } title="Pay per call with no API key at all (x402)" href="/docs/build/agent-privacy-api">
+ **Live.** An agent that starts on demand has no person to sign up or hold a
+ key. The first call gets a price back, the agent pays a small amount of
+ USDC, and the call goes through.
+
+ } title="One private swap from the agent's own wallet" href="/docs/build/agent-privacy-api">
+ **Soon.** On Solana every transfer is public, so anyone can link the paying
+ wallet to where the money went. The agent signs one funding step, and
+ Solrouter routes the swap through a mixer so the two ends are not linked.
+
+ } title="Repeated private swaps from a managed wallet" href="/docs/build/agent-privacy-api">
+ **Soon.** A long-running agent should not sign a fresh funding step for
+ every trade. Solrouter creates a wallet for the agent, keeps its key locked
+ on the server, and runs each swap on request.
+
+ } title="Plain HTTP calls and self-discovery" href="/docs/api-reference/overview">
+ **Live.** Not every language has an SDK, and some agents find services on
+ their own. Call the OpenAI-style endpoint directly, and read the discovery
+ documents that describe every route and price.
+
+
+
+## For traders
+
+These are for people who trade on Solana and want their intent and their wallet
+links kept out of provider logs.
+
+
+ } title="Swap privately from inside the chat" href="/docs/use/chat-app">
+ **Soon.** A trader wants to swap without the public ledger linking their
+ main wallet to the destination. Type the swap in chat, and a widget walks
+ you through a mixer step and the swap with your own wallet signing.
+
+
+
+**Soon.** Phoenix Copilot: describe a trading strategy in plain English and
+test it against past prices inside the sealed machine.
+
+**Soon.** RouterChan: trade from a Telegram app with a managed wallet and hard
+spending limits.
+
+## For teams
+
+These are for small companies that want private AI over their own documents
+with shared billing.
+
+
+ } title="Ask questions over your own documents" href="/docs/use/chat-app">
+ **Live.** You want answers grounded in your contracts, specs, or research
+ instead of the model's general knowledge. Upload files to a knowledge base,
+ but know that the stored pieces are not encrypted at rest.
+
+ } title="Team accounts with invites and shared funds" href="/docs/use/chat-app">
+ **Live.** A company cannot run private AI on one person's wallet. Create an
+ organization, invite members by link, and see usage per member on one
+ shared balance.
+
+
diff --git a/content/docs/use/chat-app.mdx b/content/docs/use/chat-app.mdx
new file mode 100644
index 0000000..cbddce7
--- /dev/null
+++ b/content/docs/use/chat-app.mdx
@@ -0,0 +1,87 @@
+---
+title: "Chat App"
+icon: MessageSquare
+description: "Solrouter Chat at solrouter.com/chat is a wallet-based AI chat with an encryption toggle, file attachments, and a RAG knowledge base. No email required."
+status: live
+checked: "2026-08-26"
+---
+
+import { Cards, Card } from 'fumadocs-ui/components/card';
+import { Callout } from 'fumadocs-ui/components/callout';
+import { Step, Steps } from 'fumadocs-ui/components/steps';
+import { Lock, Paperclip, Database } from 'lucide-react';
+
+Most AI chat tools want your email, store your conversations in plaintext, and lock you into a single model. Solrouter Chat at [solrouter.com/chat](https://solrouter.com/chat) works differently. You never create an account. You can turn on Maximum Privacy Mode to encrypt each prompt before it leaves your browser.
+
+You connect a Solana wallet, top up a prepaid balance, and pick one of two open-weight models. You also get file attachments and a RAG knowledge base. Encryption is a toggle. It is off by default.
+
+## Two privacy modes
+
+Encryption is a toggle, off by default. Here is what each mode does with your prompt and your history.
+
+| | Persistent (default) | Maximum Privacy (on) |
+| --- | --- | --- |
+| Prompt to the backend | plaintext | encrypted in your browser |
+| Opened where | backend, then the Nosana node | only the enclave, then the Nosana node |
+| Chat history | stored, encrypted at rest under a key Solrouter holds | not stored, lost on refresh |
+| Best for | everyday chats | sensitive prompts |
+
+For exactly who can read what, see [What is private here](/docs/use/what-is-private).
+
+## Features
+
+
+ }>
+ Turn on Maximum Privacy Mode to encrypt each prompt before it leaves your browser. Off by default.
+
+ }>
+ Send images and documents with your question. Attachments are not encrypted, only the text prompt is.
+
+ }>
+ Upload files and ask questions grounded in them. Stored chunks are not encrypted at rest.
+
+
+
+Image and video generation is Archived. It is disabled in the chat app.
+
+## Getting started
+
+Four steps take you from a blank browser tab to your first message.
+
+
+
+ ### Open the chat app
+
+ Go to [solrouter.com/chat](https://solrouter.com/chat) in your browser.
+
+
+
+ ### Connect your Solana wallet
+
+ Click **Connect Wallet** and approve the request in your wallet. Your wallet is your identity here. No email address or personal information is required.
+
+
+
+ ### Top up your balance
+
+ Add credits in **USDC** or **`$ROUTER`**. You pay per call from this prepaid balance, so you only spend on what you use.
+
+
+
+ ### Select a model and start chatting
+
+ Pick a model from the selector and send your first message. To encrypt the prompt in your browser, turn on **Maximum Privacy Mode** first. It is off by default, and history is not kept while it is on.
+
+ If the GPU node was idle, the first reply can say "Nosana GPU node is warming up". Wait a moment and send the message again.
+
+
+
+## Supported models
+
+The chat model picker lists two self-hosted open-weight models on the Nosana GPU network: `gpt-oss:20b` (Default, Live) and `qwen3.8:27b` (Uncensored, Live). No proprietary model is reachable in the chat app. Maximum Privacy Mode works with both models.
+
+For model ids and their status, see the [Supported Models](/docs/how-it-works/models) page.
+
+
+ In Maximum Privacy Mode, Solrouter's backend cannot read your prompt. Plaintext exists on your device, inside the Intel TDX enclave, and on the Nosana GPU node that runs the model during inference. Solrouter does not control that node's hardware.
+
diff --git a/content/docs/use/meta.json b/content/docs/use/meta.json
new file mode 100644
index 0000000..0110f36
--- /dev/null
+++ b/content/docs/use/meta.json
@@ -0,0 +1,9 @@
+{
+ "title": "Use Solrouter",
+ "icon": "MessageSquare",
+ "pages": [
+ "chat-app",
+ "what-is-private",
+ "pricing"
+ ]
+}
diff --git a/content/docs/use/pricing.mdx b/content/docs/use/pricing.mdx
new file mode 100644
index 0000000..5d95f6b
--- /dev/null
+++ b/content/docs/use/pricing.mdx
@@ -0,0 +1,103 @@
+---
+title: "Pricing"
+icon: CircleDollarSign
+description: "Solrouter is metered per API call. Prepay in USDC or $ROUTER from your Solana wallet. No subscription, no credit card, no email required."
+status: mixed
+checked: "2026-08-26"
+statusNote: "Prepaid billing and x402 are Live. Buyback and burn is Soon: the configured ratios are not published."
+---
+
+import { Cards, Card } from 'fumadocs-ui/components/card';
+import { Callout } from 'fumadocs-ui/components/callout';
+import { CircleDollarSign, RotateCw } from 'lucide-react';
+
+Most AI platforms make you commit before you build: a monthly subscription, a credit card on file, an email to verify. Solrouter does none of that. You pay per API call from a balance you fund yourself, so you only ever spend what you use.
+
+The setup is short. Connect a Solana wallet at [solrouter.com/sdk](https://solrouter.com/sdk), fund your balance with USDC or `$ROUTER`, generate an API key, and start building. Every product (the Privacy SDK, Agent Privacy API, MCP server, and chat app) draws from that same prepaid balance.
+
+
+ You pay per call from your prepaid balance. `GET /payments/pricing` returns the live rate table.
+
+
+## Feature status
+
+| Feature | Status |
+| --- | --- |
+| Prepaid balance in USDC or `$ROUTER` | Live |
+| Per-token metering (tables below) | Live |
+| x402 keyless payment on `POST /api/v1/x402/chat/completions` | Live |
+| `$ROUTER` buyback and burn | Soon |
+
+## Payment methods
+
+You can fund your balance two ways. The difference is what each one means for you and for the token.
+
+
+ }>
+ Pay with USDC from your Solana wallet. As a stablecoin pegged to the dollar, its value stays put, so you carry no price risk between top-ups. Top up at any time from [solrouter.com/sdk](https://solrouter.com/sdk).
+
+
+ }>
+ Pay with the native `$ROUTER` token. Fees paid in `$ROUTER` feed the buyback-and-burn mechanism. See [\$ROUTER buyback and burn](#router-buyback-and-burn) below.
+
+
+
+## Per-call rates
+
+Two rate tables exist in code. Table A bills the chat app and `POST /agent`. Table B bills the REST route `POST /api/v1/chat/completions`. `GET /payments/pricing` is the live source for table A.
+
+**Table A: chat and `/agent` billing.** Rates are USD per 1M tokens, before a 20% margin. The balance is held as app tokens at 1,000 app tokens per USD. Each billed direction has a floor of 10 app tokens (\$0.01), so a normal inference costs at least \$0.02. Charges settle in `$ROUTER` first and fall back to USDC.
+
+| Model | Input | Output |
+| --- | --- | --- |
+| `gpt-oss:20b` | \$0.10 | \$0.20 |
+| `qwen3.8:27b` | \$0.15 | \$0.30 |
+| `gemma4:31b` | \$0.15 | \$0.30 |
+
+**Table B: `POST /api/v1/chat/completions`.** Rates are USD per 1M tokens. No margin and no floor apply. Token counts are estimated from character counts (about 4 characters per token). The cost is debited from your USDC balance only. The route answers 402 when your USDC balance is zero, even if you hold `$ROUTER`.
+
+| Model | Input | Output |
+| --- | --- | --- |
+| `gpt-oss:20b` | \$0.15 | \$0.30 |
+| `qwen3.8:27b` | \$0.15 | \$0.30 |
+| `gemma4:31b` | \$0.15 | \$0.30 |
+
+The two tables disagree on `gpt-oss:20b`. Unifying them is a backend follow-up. x402 route prices come from the manifest at `https://api.solrouter.com/.well-known/x402`.
+
+## x402 keyless payments
+
+An autonomous agent often has no human around to sign up for an account or manage an API key. x402 solves that: it lets an agent pay for each call on its own, with no registration at all.
+
+x402 is a standard for HTTP-native micropayments (payments built into the web request itself), settled in USDC on Solana mainnet. The live manifest advertises Coinbase (`api.cdp.coinbase.com/x402`) as the facilitator. The manifest shows `X402_FACILITATOR_URL` when it is set, or a built-in default when it is not. It does not show which facilitator settles payments. Any x402-aware agent can discover the payment manifest and start paying immediately.
+
+* **Discovery:** `https://api.solrouter.com/.well-known/x402`, the x402 paywall manifest listing available endpoints and pricing.
+* **Endpoint:** `POST /api/v1/x402/chat/completions`. Arcium-encrypted prompt in, encrypted response out.
+* **Price:** \$0.005 per call. Solrouter's server verifies and settles the USDC payment through its facilitator and then returns the reply.
+* **Best for:** autonomous agents that self-fund their own inference costs without a human managing API keys.
+
+Going keyless costs you no privacy. The x402 path runs the same end-to-end encrypted inference as the API-key path: your prompt is still encrypted with Arcium's RescueCipher before it reaches Solrouter's backend.
+
+
+ The paywall charges \$0.005 per call. The response body of this endpoint currently reports `paid.amount: 0.02`. This is a backend follow-up; the manifest price is the one charged.
+
+
+## Managing your balance
+
+You can read your current balance straight from the SDK, so an agent or app can check funds before it spends and top up when it runs low.
+
+```typescript
+const { balance, balanceFormatted } = await client.getBalance();
+console.log(`Balance: ${balanceFormatted}`);
+```
+
+To add funds, visit [solrouter.com/sdk](https://solrouter.com/sdk) and connect your Solana wallet. Deposit USDC or `$ROUTER`. Deposit minimum: not determined.
+
+## \$ROUTER buyback and burn
+
+Status: Soon. The mechanism exists in code. The ratios are runtime settings, and the worker skips its run while they are zero.
+
+* A buyback worker reads the USDC inflow for each window and buys `$ROUTER` with a configured share of it (`BURN_USDC_BPS`).
+* A configured share of the `$ROUTER` bought back is burned (`BURN_OUTPUT_TOKEN_BPS`). The rest stays in treasury.
+* A configured share of fees paid directly in `$ROUTER` is burned on receipt (`BURN_TOKEN_BPS`). The rest stays in treasury.
+
+Configured ratios: not published. `GET /payments/buyback/log` returns the recent buyback worker ticks, including skipped ones. See [/docs/token](/docs/token) for the token supply schedule and vesting details.
diff --git a/content/docs/use/what-is-private.mdx b/content/docs/use/what-is-private.mdx
new file mode 100644
index 0000000..739cff5
--- /dev/null
+++ b/content/docs/use/what-is-private.mdx
@@ -0,0 +1,152 @@
+---
+title: "What is private here"
+icon: EyeOff
+description: "Who can read your prompt, your files, and your history, and what Solrouter keeps on its servers."
+status: mixed
+checked: "2026-08-26"
+statusNote: "Each row states its own Live or Soon status."
+---
+
+import { Callout } from 'fumadocs-ui/components/callout';
+import { Cards, Card } from 'fumadocs-ui/components/card';
+import { Lock, ShieldCheck, BookOpen, MessageSquare } from 'lucide-react';
+import { PlaintextZones } from '@/components/diagrams/plaintext-zones';
+import { PrivacyMatrix } from '@/components/diagrams/privacy-matrix';
+
+## The question
+
+"If I type something private into Solrouter, who can read it?"
+
+With encryption on, Solrouter's own servers cannot read your prompt or the reply. The prompt is opened only inside a sealed computer (a TEE) and on the rented GPU machine that runs the AI model. Your attached files, your knowledge base, and your saved chat history do not get that protection, and the tables below show exactly where each one is readable.
+
+Encryption is a toggle in the chat app. It is off by default. The Privacy SDK encrypts by default. The page [Chat app](/docs/use/chat-app) explains the toggle. This page explains what each setting exposes.
+
+## Who is who
+
+The matrix shows five parties. You are the sixth: your own device always reads your own words. Here is each party in plain words.
+
+- **You.** Your browser, or the program that uses the SDK.
+- **Network observer.** Anyone who watches the connection between you and Solrouter. For example, your internet provider or the owner of a public Wi-Fi.
+- **Solrouter backend.** Solrouter's own servers. They check your login, take payment, store your history, and pass messages along.
+- **CVM cloud host (Phala).** The company that owns the physical machine where the sealed computer runs. The sealed computer is a Confidential Virtual Machine (CVM). The processor encrypts its memory, so the machine owner cannot read it. See [What is a TEE?](/docs/how-it-works/what-is-a-tee).
+- **Nosana GPU host.** The operator of the graphics-card machine that runs the AI model. Solrouter rents it from the Nosana network. Solrouter does not control that hardware.
+- **Solana observer.** Anyone who reads the public Solana blockchain. Solrouter posts a receipt there for each encrypted request.
+
+Each cell says what that party can see. The legend under the matrix explains every word.
+
+## Who can see what
+
+Rows here describe the encrypted path: the Privacy SDK with its default settings, or the chat app with Maximum Privacy Mode on. Amber cells mark the only places a party can read your words. Every row is Live.
+
+
+
+**Notes**
+
+- **Nosana GPU host, readable.** The model runs there in plaintext for the length of one request. Solrouter rents the machine and does not control it. The request is not linked to your identity.
+- **Chat history, at rest.** Persistent mode stores each message encrypted with AES-256-GCM under a key the backend holds. That protects against a stolen database copy, not against Solrouter. On this path the backend also reads the prompt in plaintext on the way in.
+- **Knowledge-base documents.** Files are split and embedded on the server as plain text, not encrypted at rest. Whether the deployed app isolates collections per user is not determined.
+- **Attached files.** The encrypted path sends the text prompt only. Attachments travel on the default path below.
+- **Web searches** is the encrypted agent path: a REST call to `/agent` with `encryptedPrompt`, Live for REST and Soon for the SDK. Search runs through SearXNG inside the enclave, which then queries public engines. Those engines receive the search text.
+- The enclave logs the first 50 characters of each reply. Who can read that log is not determined.
+
+## Default chat (toggle off)
+
+This is the chat app with the toggle off, the SDK with `encrypted: false`, and guest chat. There is no client-side encryption, so the backend and the model node read your words. Only the rows that change from the matrix above are shown. Status: Live.
+
+
+
+On this path attachments and knowledge-base files reach the backend and the model node in plaintext. Documents upload to Cloudflare R2 through a short-lived link, and the backend extracts their text. Live search and the `web_search` tool use Brave, with DuckDuckGo and Wikipedia as fallbacks, so those services receive the search text.
+
+## Where your words are readable
+
+The strip below follows one encrypted request from your device to the Solana receipt. Green zones hold your words in readable form. Grey zones hold only ciphertext or a hash. The amber zone is the rented GPU machine.
+
+
+
+**In words**
+
+- Your device: your words are readable here. Your browser or program scrambles them before they leave.
+- Network: ciphertext only. A watcher sees size and timing.
+- Solrouter backend: ciphertext only. It checks your login, bills you, and passes the blob along.
+- TDX CVM: your words are readable here, inside memory that the processor encrypts. The machine owner cannot open it.
+- Nosana GPU node: your words are readable here while the model runs. Solrouter does not control this machine. The request is not linked to you.
+- Solana: hash only. A receipt proves a request happened and names the model. It does not hold your words.
+
+
+ Solrouter does not run fully homomorphic encryption (FHE) inference. FHE means a computer works on scrambled data without ever unscrambling it. No production system runs AI models of this size under FHE in 2026. The compute cost is many orders of magnitude away from usable speed. Anyone who claims "FHE LLM inference" in production is overclaiming.
+
+ What Solrouter provides is encryption on your device, a hardware-isolated CVM that unscrambles the prompt, a model that runs on a rented Nosana GPU node, and a receipt on Solana for each encrypted request. That is a real and checkable guarantee. It is not FHE, and we will not claim otherwise.
+
+
+## What we keep
+
+Retention periods are not published. Each row states what is stored, in what form, who holds the key, and how to remove it. Rows are Live unless marked.
+
+
+
+| What | Where | Format | Key holder | How to delete | Retention |
+| --- | --- | --- | --- | --- | --- |
+| Chat rows (`enc:v1:`) | Solrouter's database, tables `chat_messages` and `chats` (message text, chat title, search and knowledge-base context, pitch-deck cards) | Scrambled with AES-256-GCM, stored as text with the prefix `enc:v1:` | Solrouter backend, from `CHAT_CONTENT_KEK` or `WALLET_VAULT_KEK` in the server settings | Deleting a chat in the app marks it archived. The rows stay in the database. A hard delete path: not determined | not published |
+| Memory envelope (`umem:v1:`) | Solrouter's database, table `user_memory`, one row per user | Scrambled in your browser with AES-256-GCM, stored as text with the prefix `umem:v1:`. Solrouter cannot read it | You. The key comes from your wallet signature and is never stored | "Forget all" in the app removes the row (`DELETE /memory`) | not published |
+| Knowledge-base chunks | Files on the backend server disk, one JSON file per collection under `data/vectors/` | Plain text chunks plus embedding vectors. Not encrypted | none | Delete the whole collection (`DELETE /rag/collections/:name`). Delete of one document: not determined | not published |
+| Uploaded files (R2) | A Cloudflare R2 bucket, key `documents/` plus a timestamp and a random id | The original file. Not encrypted by Solrouter | none | not determined. The code has upload and download, no delete | not published |
+| Usage log | Solrouter's database, table `api_usage` | Plain rows: key id, user id, model, token counts, cost, request id, time. No prompt text | none | not determined | not published |
+| Swap session rows (Soon) | Solrouter's database, table `agent_swap_sessions` | Plain rows: mode, state, tokens, amount, destination address, transaction ids, payer id, webhook URL. The one-shot signer key is scrambled and set to null when the swap ends | Solrouter backend, `WALLET_VAULT_KEK`, for the signer key only | not determined. The API has read and webhook routes, no delete | not published. Pending sessions expire after 7 days |
+| Guest per-IP counter | Backend process memory, not a database | Your internet address, a message count, and a reset time | none | No route. The entry resets 24 hours after first use and vanishes when the server restarts | not published |
+
+
{label}
@@ -39,35 +43,60 @@ function Hop({ label }: { label: string }) {
);
}
-/** Clean, theme-adaptive infographic of the encrypt → blind-relay → TEE flow. */
-export function EncryptionFlow() {
+/**
+ * Theme-adaptive infographic of the request path.
+ *
+ * encrypted (default): device encrypts, backend relays ciphertext, the CVM
+ * decrypts and calls the model on a Nosana GPU node, the reply comes back
+ * encrypted.
+ *
+ * encrypted={false}: the same path with plaintext at the backend. Used on the
+ * Privacy SDK page to show what `encrypted: false` gives up.
+ */
+export function EncryptionFlow({ encrypted = true }: { encrypted?: boolean }) {
+ const wire = encrypted ? 'ciphertext' : 'plaintext';
+ const label = encrypted
+ ? 'Request path with encryption on: your device encrypts the prompt, the Solrouter backend relays ciphertext it cannot read, the Intel TDX enclave decrypts it and calls the model on a Nosana GPU node, and the reply returns encrypted to your device.'
+ : 'Request path with encryption off: your device sends plaintext, the Solrouter backend reads and routes it to the same self-hosted model on a Nosana GPU node, and the reply returns in plaintext.';
+
return (
-
+
-
+
-
+
+
+
-
- The response is re-encrypted inside the enclave — only your device can
- read it.
-
-
+
+ {encrypted
+ ? 'The reply is encrypted inside the enclave with your session key. Only your device can read it.'
+ : 'The reply returns in plaintext. No enclave, no on-chain receipt.'}
+
+
);
}
diff --git a/src/components/diagrams/plaintext-zones.tsx b/src/components/diagrams/plaintext-zones.tsx
new file mode 100644
index 0000000..e1b99a9
--- /dev/null
+++ b/src/components/diagrams/plaintext-zones.tsx
@@ -0,0 +1,106 @@
+import { Cpu, Database, Link2, Server, User, Zap, type LucideIcon } from 'lucide-react';
+
+type Zone = {
+ icon: LucideIcon;
+ title: string;
+ state: string;
+ plaintext: boolean;
+ attacker: string;
+};
+
+const ZONES: Zone[] = [
+ {
+ icon: User,
+ title: 'Your device',
+ state: 'Plaintext',
+ plaintext: true,
+ attacker: 'your prompt and the reply',
+ },
+ {
+ icon: Link2,
+ title: 'Network',
+ state: 'Ciphertext',
+ plaintext: false,
+ attacker: 'ciphertext and traffic timing',
+ },
+ {
+ icon: Server,
+ title: 'Solrouter backend',
+ state: 'Ciphertext',
+ plaintext: false,
+ attacker: 'ciphertext, your wallet or key, the model name',
+ },
+ {
+ icon: Cpu,
+ title: 'TDX enclave',
+ state: 'Plaintext in CPU-encrypted memory',
+ plaintext: true,
+ attacker: 'encrypted memory, not the text',
+ },
+ {
+ icon: Zap,
+ title: 'Nosana GPU node',
+ state: 'Plaintext in the Ollama process, TLS in transit',
+ plaintext: true,
+ attacker: 'your prompt and the reply, not who you are',
+ },
+ {
+ icon: Database,
+ title: 'Solana',
+ state: 'Hash only',
+ plaintext: false,
+ attacker: 'a hash of the ciphertext and the model name',
+ },
+];
+
+/**
+ * Where the prompt exists as readable text on the encrypted path.
+ * Plaintext zones use the primary tint; ciphertext and hash-only zones use
+ * the muted tint. Each zone carries a one-line "an attacker here sees" label.
+ */
+export function PlaintextZones() {
+ return (
+
+
+ {ZONES.map((zone) => (
+
+
+ An attacker here sees: {zone.attacker}
+
+
+
+
+
+
{zone.title}
+
+ {zone.state}
+
+
+
+ ))}
+
+
+
+
+ Readable text exists here
+
+
+
+ Only ciphertext or a hash exists here
+
+
+
+ );
+}
diff --git a/src/components/diagrams/privacy-matrix.tsx b/src/components/diagrams/privacy-matrix.tsx
new file mode 100644
index 0000000..5a29e4a
--- /dev/null
+++ b/src/components/diagrams/privacy-matrix.tsx
@@ -0,0 +1,89 @@
+import type { ReactNode } from 'react';
+
+/** Cell tokens. `pt` (readable) is the only one that means a party can read your words. */
+export type Cell = 'pt' | 'ct' | 'no' | 'ha' | 're' | 'me' | 'nd';
+
+const STYLE: Record = {
+ pt: { label: 'readable', cls: 'bg-amber-500/15 text-amber-600 dark:text-amber-300 border border-amber-500/40' },
+ ct: { label: 'encrypted', cls: 'bg-emerald-500/15 text-emerald-600 dark:text-emerald-300 border border-emerald-500/40' },
+ no: { label: 'nothing', cls: 'bg-fd-muted text-fd-muted-foreground border border-fd-border' },
+ ha: { label: 'hash only', cls: 'bg-sky-500/15 text-sky-600 dark:text-sky-300 border border-sky-500/40' },
+ re: { label: 'at rest*', cls: 'bg-amber-500/10 text-amber-600 dark:text-amber-200 border border-amber-500/30' },
+ me: { label: 'metadata', cls: 'bg-fd-muted text-fd-muted-foreground border border-fd-border' },
+ nd: { label: 'unknown', cls: 'text-fd-muted-foreground border border-dashed border-fd-border' },
+};
+
+const LEGEND: { token: Cell; text: string }[] = [
+ { token: 'pt', text: 'readable: this party can read your words' },
+ { token: 'ct', text: 'encrypted: sees only ciphertext, holds no key' },
+ { token: 'no', text: 'nothing: never reaches this party' },
+ { token: 'ha', text: 'hash only: a fingerprint, not your words' },
+ { token: 're', text: 'at rest: stored encrypted under a key Solrouter holds' },
+ { token: 'me', text: 'metadata: size or timing, not content' },
+];
+
+function Pill({ token }: { token: Cell }) {
+ const s = STYLE[token];
+ return (
+
+ {s.label}
+
+ );
+}
+
+export type MatrixRow = { what: ReactNode; cells: Cell[] };
+
+/**
+ * Threat-model matrix. Each row is a kind of data; each column is a party;
+ * each cell says what that party can see. Amber cells are the only exposure.
+ */
+export function PrivacyMatrix({
+ parties,
+ rows,
+ legend = true,
+}: {
+ parties: string[];
+ rows: MatrixRow[];
+ legend?: boolean;
+}) {
+ return (
+
+ );
+}
+
+/**
+ * The sealed-room picture of a Confidential VM (Intel TDX on Phala dStack).
+ * Two layers: isolation (the operator cannot open the door) and attestation
+ * (the window shows which program runs inside). The Nosana GPU node sits
+ * outside the room and sees the prompt while it runs the model.
+ */
+export function SealedRoom() {
+ return (
+
+
+
+
+ Data center (cloud host)
+
+
+
+
+
+
+
+
Operator
+
+ Cannot open the door: memory is encrypted by the CPU
+
+
+
+
+
+ Confidential VM (the sealed room)
+
+
+
+
+
+
+
+
+
+
+
+
+
Nosana GPU node (outside the room)
+
+ Runs the model. Sees the prompt while it works. Does not know who you are.
+
+
+
+
+
+
+ Isolation. The CPU encrypts the room's memory. The host and the operator cannot read it.
+
+
+
+ Attestation. The CPU signs a note that names the program inside. You can check that note.
+
+ ))}
+
+ ) : null}
+
+ );
+}
diff --git a/src/components/verify/key-quote-inspector.tsx b/src/components/verify/key-quote-inspector.tsx
new file mode 100644
index 0000000..74e8911
--- /dev/null
+++ b/src/components/verify/key-quote-inspector.tsx
@@ -0,0 +1,150 @@
+'use client';
+
+import { BadgeCheck, CircleAlert, Loader2, RefreshCw } from 'lucide-react';
+import { useState } from 'react';
+
+// Live, CORS-enabled read endpoints (checked 2026-08-26 with an Origin header):
+// GET /tee/public-key -> { publicKey, publicKeySha256, algorithm, teeType }
+// GET /tee/attestation -> { teeType, teePublicKey, teePublicKeySha256, reportDataHex, tdxQuote, generatedAt }
+// The GET quote pins report_data = sha256(X25519 public key). This widget recomputes
+// that hash in the browser and compares it with reportDataHex. Override the host
+// with NEXT_PUBLIC_API_BASE for local testing.
+const API_BASE = process.env.NEXT_PUBLIC_API_BASE || 'https://api.solrouter.com';
+
+type PublicKey = { publicKey: string; publicKeySha256?: string; algorithm?: string; teeType?: string };
+type Attestation = {
+ teeType?: string;
+ teePublicKey?: string;
+ teePublicKeySha256?: string;
+ reportDataHex?: string;
+ tdxQuote?: unknown;
+ tdxQuoteError?: string;
+ generatedAt?: number;
+};
+
+type Result = {
+ teeType: string;
+ keyMatches: boolean;
+ hashMatches: boolean;
+ quotePresent: boolean;
+ quoteError?: string;
+ computedSha256: string;
+ reportDataHex: string;
+ generatedAt?: string;
+};
+
+function base64ToBytes(b64: string): Uint8Array {
+ const bin = atob(b64);
+ const out = new Uint8Array(bin.length);
+ for (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i);
+ return out;
+}
+
+async function sha256Hex(bytes: Uint8Array): Promise {
+ const digest = await crypto.subtle.digest('SHA-256', bytes as BufferSource);
+ return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, '0')).join('');
+}
+
+export function KeyQuoteInspector() {
+ const [busy, setBusy] = useState(false);
+ const [error, setError] = useState(null);
+ const [result, setResult] = useState(null);
+
+ async function run() {
+ setBusy(true);
+ setError(null);
+ setResult(null);
+ try {
+ const [keyRes, attRes] = await Promise.all([
+ fetch(`${API_BASE}/tee/public-key`),
+ fetch(`${API_BASE}/tee/attestation`),
+ ]);
+ if (!keyRes.ok) throw new Error(`GET /tee/public-key returned ${keyRes.status}`);
+ if (!attRes.ok) throw new Error(`GET /tee/attestation returned ${attRes.status}`);
+ const key = (await keyRes.json()) as PublicKey;
+ const att = (await attRes.json()) as Attestation;
+ const computed = await sha256Hex(base64ToBytes(key.publicKey));
+ const reportDataHex = (att.reportDataHex || '').toLowerCase();
+ setResult({
+ teeType: att.teeType || key.teeType || 'unknown',
+ keyMatches: !!att.teePublicKey && att.teePublicKey === key.publicKey,
+ hashMatches: reportDataHex.startsWith(computed),
+ quotePresent: att.tdxQuote !== null && att.tdxQuote !== undefined,
+ quoteError: att.tdxQuoteError,
+ computedSha256: computed,
+ reportDataHex,
+ generatedAt: att.generatedAt ? new Date(att.generatedAt).toISOString() : undefined,
+ });
+ } catch (e) {
+ setError(e instanceof Error ? e.message : String(e));
+ } finally {
+ setBusy(false);
+ }
+ }
+
+ const ok = result && result.keyMatches && result.hashMatches && result.quotePresent;
+
+ return (
+
+
+
+
+ Fetches /tee/public-key and /tee/attestation from your browser.
+
+
+
+
+ {error ? (
+
+
+ {error}
+
+ ) : null}
+ {result ? (
+
+
+ {ok ? : }
+ {ok ? 'The published key is bound into the live TDX quote.' : 'Something did not match. Read the rows below.'}
+
+
+
+
+
+
+
+
+
+
+ {result.generatedAt ? : null}
+
+
+
+
+ This check proves the key you encrypt to is the key the quote names. It does not verify the Intel
+ signature chain. For that, run the quote through Intel DCAP tools.
+