# Ambient Full LLM Context This file gives language models and AI agents a concise, canonical description of Ambient. Public Ambient website content is intentionally available for search indexing, real-time AI input, and AI training. ## Canonical Summary Ambient is a Proof of Work AI blockchain and verified inference network. It makes high-scale machine intelligence available as a neutral utility by letting users, applications, enterprises, and autonomous agents verify that a specific model ran on a specific prompt and produced a specific output at a specific time. Ambient's core identity is verified AI infrastructure for the agentic economy - not a decentralized model host or generic crypto AI marketplace. Its technical and economic design aligns network security with useful AI work. ## Verified Inference and Proof of Logits Verified inference lets a user or system prove that the requested model ran on the requested prompt and produced the returned output. It does not prove the answer is factually true; it proves what produced the answer, which is the foundation for truth checks, safety checks, audits, and accountability. Ambient's verification is called Proof of Logits. Logits are the raw numerical outputs a model uses to determine token probabilities; they act like fingerprints of a model's execution. Nodes commit to the logit distribution before sampling, and validators independently re-check the proof - a miner may generate thousands of tokens, but a validator only needs to re-run a single step to verify the whole output. Producing the work is expensive; verifying it is cheap. ## Useful Proof of Work Bitcoin's Proof of Work secures a network through hashing. Ambient applies Proof of Work to AI: miners perform useful machine intelligence work (inference and future model improvement) while securing the network. Users and agents need inference; miners provide it and earn rewards; verification makes the service trustworthy; demand improves miner economics, which improves capacity and quality. ## Products and API Ambient exposes an OpenAI- and Anthropic-compatible API at https://api.ambient.xyz/v1, so developers can point existing SDKs at Ambient and go. Every response ships with Proof of Logits, at no separate fee. Zero data retention is the default. ### Models (3) - GLM 5.2 (ambient/large): 198K context, $0.60 input / $2.00 output per million tokens. - Qwen3.6 27B (qwen/qwen3.6-27b): 32K context, $0.32 input / $3.20 output per million tokens. - Qwen3.8 27B (qwen/qwen3.8-27b): 32K context, $0.32 input / $3.20 output per million tokens. ## Enterprise Value Ambient gives enterprises AI infrastructure they can verify: model provenance, verification receipts, auditability, privacy-preserving inference, stable execution targets, and API compatibility. ## Frequently Asked Questions Q: What is verified inference? A: A cryptographic proof (Proof of Logits) that a specific model produced a specific output, so you're not taking the provider's word for it. Q: Is there an extra charge for verification? A: No. Verification is built into the network, not a paid add-on. Q: How is this different from a closed provider? A: Closed APIs are black boxes: the model, routing, and guardrails can change without notice, and your data may be retained. Ambient is verifiable, open, and zero-retention. Q: Do you keep my data? A: No. Zero data retention is the default, and node operators agree to the same policy. End-to-end encryption is available for enterprise. Q: Which models can I run? A: 3 open models including GLM 5.2, via OpenAI- and Anthropic-compatible endpoints. Q: How can I pay? A: For everyday use: pay-as-you-go, prepaid credits, or a monthly plan. You can also pay with crypto via x402. x402 subscriptions are coming soon. Q: What is x402? A: x402 is an open standard for paying for online services with crypto, trustlessly and per request, without a traditional account. It's a natural fit for AI agents that buy inference on demand. You can use x402 to pay per request on Ambient today; subscription support is coming soon. ## Links - Website: https://ambient.xyz - App: https://app.ambient.xyz - Docs: https://ambient.xyz/docs - X: https://x.com/ambient_xyz - Discord: https://discord.gg/CzDH8ybEUU --- # Ambient Docs — Markdown Export The sections below are the complete Ambient documentation pages as Markdown, in navigation order. Each page is individually fetchable by appending ".md" to its canonical URL (e.g. https://ambient.xyz/docs/get-started.md). --- # Get started > Point any OpenAI- or Anthropic-compatible client at Ambient's API and make your first request against the verified inference network. - Canonical: https://ambient.xyz/docs/get-started --- Ambient exposes an OpenAI-compatible API and an Anthropic-compatible API, so existing SDKs and tools work by swapping the base URL: point OpenAI-style clients at `https://api.ambient.xyz/v1`, and point the Anthropic SDK at `https://api.ambient.xyz` (the SDK appends the `/v1` itself). You'll need an API key, which you create in the [Ambient app](https://app.ambient.xyz). ## Where to go Developers building against the API are in the right place: keep reading, then see [Learn](https://ambient.xyz/docs/learn) for how verification works. If you want chat, research, keys, and billing in the web app, that lives under [Use Ambient](https://ambient.xyz/docs/use). Mining is live in curated waves; [Run a node](https://ambient.xyz/docs/mine) covers hardware and onboarding. Organizations evaluating Ambient should start with [Enterprise](https://ambient.xyz/docs/enterprise) for posture and deployment. ## See what's available The model catalog endpoint requires no authentication, so you can explore the network before creating a key: ```bash curl https://api.ambient.xyz/v1/models ``` Each model entry includes pricing, context limits, and capability flags. Anything listed is served: GLM 5.2 (`ambient/large`) is the supported production model, and other listed models may be previews with no guarantees. The `is_ready` field is an OpenRouter routing flag, not an availability signal, so don't gate on it. ## Endpoints at a glance | Endpoint | Auth | Purpose | | --------------------------- | ---------- | ---------------------------------------- | | `GET /v1/models` | None | List models, pricing, and capabilities | | `POST /v1/chat/completions` | Bearer key | OpenAI-compatible chat completions | | `POST /v1/messages` | Bearer key | Anthropic-compatible messages | > [!TIP] Before your first request > Many Ambient models are reasoning models: with a small `max_tokens` the > budget is spent in the reasoning channel and `content` comes back null, so > use a larger `max_tokens` (or a non-reasoning model). And a `429` with "No workers available" > is a capacity signal, not rate limiting: retry with short, jittered backoff > or fail over to another listed model. See > [Errors and retries](https://ambient.xyz/docs/build/errors). ## Next steps Create an API key in the [Ambient app](https://app.ambient.xyz) and run the [quickstart](https://ambient.xyz/docs/get-started/quickstart). The [model catalog](https://ambient.xyz/docs/build/models) shows what's serving today, and [Learn](https://ambient.xyz/docs/learn) explains how Proof of Logits verification works. --- # Quickstart > Create an API key, make your first request against the Ambient network, and understand what comes back, all in under five minutes. - Canonical: https://ambient.xyz/docs/get-started/quickstart --- A first completion against `https://api.ambient.xyz/v1` takes a key and one request. The API is OpenAI-compatible, so an existing client only needs a new base URL and key. ### 1. Get an API key Create a key at [app.ambient.xyz/keys](https://app.ambient.xyz/keys). Requests authenticate with a standard bearer header: ```text Authorization: Bearer $AMBIENT_API_KEY ``` The model catalog endpoint requires no authentication, so you can browse the network before you have a key: ```bash curl https://api.ambient.xyz/v1/models ``` > [!NOTE] > Because `GET /v1/models` is unauthenticated, a successful call to it does > not prove your key works. Only a real completion (like the one below) > validates a key. ### 2. Make your first request The examples use `ambient/large`, an Ambient-managed alias for GLM 5.2, the supported production model. Any model id from [`GET /v1/models`](https://ambient.xyz/docs/build/models) works: everything listed is served (the `is_ready` field is an OpenRouter routing flag, not an availability signal). #### curl ```bash curl https://api.ambient.xyz/v1/chat/completions \ -H "Authorization: Bearer $AMBIENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ambient/large", "messages": [ {"role": "user", "content": "Say hello from Ambient."} ], "max_tokens": 512 }' ``` `max_tokens` is 512 because it caps reasoning and answer combined. Reasoning models can spend a small budget entirely on thinking and return `null` content. #### Python ```python title="quickstart.py" import os from openai import OpenAI client = OpenAI( base_url="https://api.ambient.xyz/v1", api_key=os.environ["AMBIENT_API_KEY"], ) response = client.chat.completions.create( model="ambient/large", messages=[{"role": "user", "content": "Say hello from Ambient."}], # max_tokens caps reasoning + answer combined; reasoning models can # spend a small budget entirely on thinking and return null content. max_tokens=512, ) message = response.choices[0].message # Reasoning arrives on `reasoning` or `reasoning_content` depending on # the model. Check both. reasoning = getattr(message, "reasoning", None) or getattr( message, "reasoning_content", None ) if reasoning: print("Reasoning:", reasoning) print("Response:", message.content) ``` #### TypeScript ```ts title="quickstart.ts" import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.ambient.xyz/v1", apiKey: process.env.AMBIENT_API_KEY, }); const response = await client.chat.completions.create({ model: "ambient/large", messages: [{ role: "user", content: "Say hello from Ambient." }], // max_tokens caps reasoning + answer combined; reasoning models can // spend a small budget entirely on thinking and return null content. max_tokens: 512, }); const message = response.choices[0].message; // Reasoning arrives on `reasoning` or `reasoning_content` depending on // the model. Check both. const reasoning = (message as { reasoning?: string }).reasoning ?? (message as { reasoning_content?: string }).reasoning_content; if (reasoning) console.log("Reasoning:", reasoning); console.log("Response:", message.content); ``` If the request returns `429` with a message like `"No workers available"` or `"Upstream request failed"`, the model has no capacity at the moment. That is not a rate limit: retry with short, jittered backoff, or fail over to another listed model, and see [Errors and retries](https://ambient.xyz/docs/build/errors). ### 3. What you got back The body is a standard OpenAI-style chat completion: | Field | What it is | | --- | --- | | `id` | Completion id (`chatcmpl-…`) | | `choices[0].message.content` | The answer text | | `choices[0].message.reasoning` | The model's thinking trace, when the model exposes one (some models use `reasoning_content`) | | `choices[0].finish_reason` | `stop` for a clean finish; `length` means the token budget ran out | | `usage` | Token counts, including `completion_tokens_details.reasoning_tokens` | Every inference also returns an `inference-id` response header, a stable identifier for the request (also visible as `x-request-id` and embedded in the completion `id`). Log it: it is the handle for the request on the network. ### 4. Next steps - [Models and readiness](https://ambient.xyz/docs/build/models) covers the catalog, pricing from the API, and what `is_ready` does and doesn't mean. - [Streaming](https://ambient.xyz/docs/build/streaming) explains SSE chunks and how reasoning deltas differ from content deltas. - [Errors and retries](https://ambient.xyz/docs/build/errors) is the full error taxonomy. - [Verified inference](https://ambient.xyz/docs/build/verified-inference) documents the verification request flags and their current status. - The [OpenAI SDK](https://ambient.xyz/docs/build/openai-sdk) and [Anthropic SDK](https://ambient.xyz/docs/build/anthropic-sdk) guides cover full SDK setup. --- # Using the web app > Sign in at app.ambient.xyz to chat with the network model, run Research mode, generate API keys, monitor usage, manage teams, claim Drops, and handle billing. - Canonical: https://ambient.xyz/docs/get-started/web-app --- Ambient runs on a Solana-compatible proof-of-work Layer-1 blockchain and provides fast, verified AI inference via a large language model. The web app at **app.ambient.xyz** lets you interact with this model via chat, perform research tasks, manage API keys and teams, monitor usage, and handle billing. The platform is currently in a pre-testnet alpha, so features and performance may evolve over time. ## Sign up and log in - Visit [app.ambient.xyz](https://app.ambient.xyz) and log in with your credentials (e.g., Auth0). If you don't yet have access, contact the Ambient team for an invite. - Once authenticated, you'll see the main dashboard with a sidebar containing links to **New Chat**, **API Keys**, **Usage**, **Team**, **Drops**, **Billing**, **Docs**, and **Support**. ## Chatting with Ambient - Click **New Chat** to open a fresh conversation window. The chat interface is labelled **"Ask Ambient…"** and lets you interact with the AI. - Type your question in the input box and press the send arrow to receive an answer. For more in-depth queries, you can switch to **Thinking** or **Research** mode using the drop-down next to the chat header. - **Thinking** mode takes a bit longer but aims to deliver more thoughtful answers. - **Research** mode performs wider retrieval and produces more detailed, citation-rich responses. ## Research mode - To access research, click the drop-down next to **Chat** and select **Research**. The header will change to **"Research with Ambient…"**. - Enter your research prompt; the AI will gather information, synthesize it and provide a thorough answer, often with references. - Use research for tasks such as literature reviews, background reports or complex summaries. ## Generating API keys Developers can integrate Ambient into their own applications via a Web2 API. ### 1. Open the API Keys page From the sidebar, select **API Keys**. You'll see a page with the **Web2 API URL** at the top and a section labelled **Keys**. ### 2. Create a key Click **Create new API key**. Ambient will generate a secret token. Keep it private. ### 3. Copy an example snippet Below the keys list, you'll find example code snippets (cURL, JavaScript and Python) showing how to call the chat/completions endpoint using your new key. ### 4. Build against the API Use the API to build your own applications or automate tasks by sending chat prompts and receiving model responses programmatically. ## Monitoring usage - The **Usage** page displays charts for prompt tokens, completion tokens and request counts, helping you track consumption over time. - You can filter by timeframe and inspect usage per API key, which is especially useful for budgeting and optimization. ## Team management - Navigate to **Team** to manage collaboration. You can create multiple teams and switch between them via a drop-down at the top. - Each team page lists members with columns for **Name**, **Email**, **Role** and **Actions**. - Use **Add team member** to invite colleagues via email. - Assign roles (e.g., "manager") to control permissions. - Remove members or edit the team name as needed. ## Drops (test tokens) - **Drops** let you request testnet AMB tokens for experimentation. These credits have no real monetary value and are intended solely for sandbox use. - Follow the on-screen instructions to request tokens, but note that they cannot be traded or withdrawn. ## Billing and credits - The **Billing** page shows your available credits and token pricing. As of the testnet phase, the cost is roughly $1.40 per million input tokens and $4.40 per million output tokens. - Purchase credits to fund API usage. You can also enable or disable auto-top-up (if supported), which automatically purchases more credits when your balance runs low. ## Documentation and support - The **Docs** section provides API reference material and integration guides. - Use **Support** to submit tickets or report issues. The Ambient team is actively refining the alpha product, so feedback is welcome. ## Keep going - [Ambient web app](https://ambient.xyz/docs/use/app) is the surface-by-surface reference for Chat, Research, and API Keys. - [Build](https://ambient.xyz/docs/build) covers calling the API from your own code once you have a key. --- # Learn > The concepts behind Ambient: what the network is, how Proof of Logits verifies inference, how requests flow, and where economics stand. - Canonical: https://ambient.xyz/docs/learn --- Verified inference lets a user or system prove that the requested model ran on the requested prompt and produced the returned output. It does not prove the answer is factually true. It proves what produced the answer, which is what audits and accountability need. The pages in this section explain the mechanism and the network built around it. ## The concept pages - [What is Ambient?](https://ambient.xyz/docs/learn/what-is-ambient) is the one-page answer: why the network exists, the single-model thesis, and how the pieces fit. - [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits) covers the verification mechanism itself: logit fingerprints, progress markers, one-token spot checks, and work-credit penalties. - [Network architecture](https://ambient.xyz/docs/learn/architecture) covers the four roles and the life of a request, from auction to settlement. - [Testnet](https://ambient.xyz/docs/learn/testnet) covers the live testnet: external services, the on-chain Ambient Main Program, the off-chain miner/validator components, and how to take part. - [Tokenomics](https://ambient.xyz/docs/learn/tokenomics) covers the reward design and the current state of network economics. ## Where you fit Users of the web app and Desktop should head to [Use Ambient](https://ambient.xyz/docs/use); developers, to [Get started](https://ambient.xyz/docs/get-started) for a first request. [Run a node](https://ambient.xyz/docs/mine) covers hardware requirements and onboarding for miners, and [Enterprise](https://ambient.xyz/docs/enterprise) covers posture and deployment for organizations. --- # What is Ambient? > Ambient is an SVM-compatible proof-of-work L1 that serves verified AI inference from one continuously improving, open-weights foundation model. - Canonical: https://ambient.xyz/docs/learn/what-is-ambient --- *Truly open AI, powered by AI Bitcoin.* Ambient is a Solana-compatible (SVM), proof-of-work Layer 1 blockchain that turns decentralized GPU compute into one continuously improving, open-weights foundation model, then verifies that model's outputs. It delivers the privacy, censorship resistance, and cost profile of crypto AI with the speed, uptime, and reliability developers expect. ## Why Ambient exists Two problems motivate the network. The first is that closed AI is powerful but risky: a centralized provider can change model behavior, raise prices, restrict access, censor outputs, or compete with the applications built on top of it. The second is that current crypto-AI networks underdeliver. Proof-of-stake model "marketplaces" have low utilization, stale models, inconsistent quality, and limited incentives for new compute to join; verified inference has not been practical at these scales (ZK approaches carry roughly 1000x overhead, optimistic approaches carry asymmetric risk); and decentralized training has been too inefficient to be usable. Ambient's response: one large model (600B+ parameters) and its fine-tunes, verified inference with less than 0.1% overhead, training designed to run efficiently across the network, and a proof-of-work scheme where the work itself is useful inference. ## The single-model thesis Rather than a marketplace of many models, Ambient concentrates the network on that one model. Users avoid a paradox of choice, agents avoid depending on models of unknown provenance, and miners get steady utilization instead of paying constant model download-and-load costs. Ambient's mission, from the [Ambient Litepaper](https://ambient.xyz/Ambient_Litepaper_V1.pdf): > an AI secured blockchain ten times more efficient than incumbent systems > with built-in privacy and censorship resistance that runs a single, huge, > highly performant, auditable, and transparent model (and its fine tunes) at > low latency… ## Compared to Bitcoin's proof of work Ambient frames itself as the next step for proof of work: keep the security model, change what the work produces. Bitcoin's miners compute hashes that have no value outside securing the chain; Ambient's miners run inference that somebody wanted anyway. | | Bitcoin | Ambient | | --- | --- | --- | | Network security | Proof of work | Useful proof of work | | Hash power potential | ASICs, steady | GPUs, exponentially increasing | | What the work is | Hashing | AI inference on one large model | | Throughput target | ~7 TPS | ~65,000 TPS | | Deflationary bet | Fixed supply | AI demand increases | The throughput figure is the SVM-derived design target, not a measured testnet number. ## How Ambient works 1. **Proof of Logits (PoL).** Verified inference is the work. During generation, the model's internal logits (pre-softmax scores) form a unique fingerprint of its computation. Miners commit hashed progress markers of these logits; a validator can check a response by recomputing just one token and comparing hashes. Expensive to generate, cheap to validate. See [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits). 2. **Continuous PoL and leader election.** The network continuously measures validated work from inference, fine-tuning, and training. Leaders are elected based on recent logit stake (LStake), contribution to useful work, measured rather than a locked token stake, while transaction ordering stays Solana-fast and non-blocking. 3. **Query auction and quality of service.** Users and agents post requests with a desired latency and price; miners bid to serve them, each posting a deposit that is returned when the query completes on time and forfeited if it does not. Validators are selected with LStake-weighted randomness. See [Network architecture](https://ambient.xyz/docs/learn/architecture). ## Where the network stands today The paid API is live at `api.ambient.xyz`, the chain is running as a testnet, and mining onboarding runs in curated waves. ## Keep reading - [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits): the verification mechanism in depth - [Network architecture](https://ambient.xyz/docs/learn/architecture): roles and the life of a request - [Tokenomics](https://ambient.xyz/docs/learn/tokenomics): how the reward design works - [Get started](https://ambient.xyz/docs/get-started): make your first API request --- # Proof of Logits > How Ambient verifies that a specific model produced a specific output: logit fingerprints, progress markers, and cheap spot-check validation. - Canonical: https://ambient.xyz/docs/learn/proof-of-logits --- Proof of Logits (PoL) is Ambient's mechanism for verified inference: proving that a particular model generated a particular piece of text. For the full protocol treatment, see the [Ambient Litepaper](https://ambient.xyz/Ambient_Litepaper_V1.pdf). ## Logits are fingerprints Logits are the raw, unnormalized outputs of a model's last layer, before an activation function like softmax turns them into token probabilities. For every token an LLM generates, it first produces a logit value for each token in its vocabulary. The combination of all logits produced during a generation is a unique fingerprint of the model's computation at every step, and hashing reduces that fingerprint to a single number. One nuance matters: identical models on different hardware can produce slightly different floating-point results. Ambient generates hardware-agnostic representations of the logits themselves, so two machines faithfully running the same model produce the same fingerprint. ## Per-token commitments and progress markers For each generated token, the miner hashes the logits that produced it. The overall proof is a hash over that list of hashes. For tokens `n` through the final token `t`: ```text PoL hash = Hash(Hash(n) ... Hash(t)) ``` A **progress marker** is the hash of the logits at a chosen point `x` tokens into the output. With the input, the output, and progress markers in hand, a validator does not need to reproduce the whole generation; it only needs to re-run inference from one token prior up to a given marker. ## Validator sampling Validation is a four-step spot check: ### 1. Miner produces text The miner runs full inference, generating the response and committing logit hashes along the way. ### 2. Validator picks a random point A validator selects a random token in the output and requests the miner's "state of thinking" (the logit hash) at that point. ### 3. Validator re-runs one token The validator runs a single token of inference on the same context with the same model, producing its own state-of-thinking hash. ### 4. Hashes must match If the hashes match, the output is validated. A single token of inference checks an entire generation. ## A worked example Take a model whose entire vocabulary is four words, and a query whose output is "the rain in Spain". For the first output token, the model produces a logit for each vocabulary word; the largest one wins, and the miner hashes that logit vector. To check the token, a validator runs a single token of inference on the same context and hashes its own logits. If the hashes match, that token is proven. [Diagram: `A four-word vocabulary: Spain (0), the (1), in (2), rain (3). The output is "the rain in Spain". For the first token, the miner's logits are [0, 3.7, -1, 2] across the four vocabulary positions; position 1 ("the") has the highest logit, 3.7, so "the" is generated. The hash of those logits is b9776d7 (illustrative). A validator re-runs a single token of inference on the same context, produces the same logits [0, 3.7, -1, 2], hashes to the same value b9776d7, and the token is verified.`] *`The worked example: the first token "the" wins with a logit of 3.7, and its logit hash (b9776d7, illustrative) is what a validator reproduces from one token of inference.`* The economics come from asymmetry: generating a response might cost, say, 4,000 tokens of inference, while validating it costs 1. The scheme is conceptually similar to what Bitcoin does with hashing, except here the computation does useful work. This asymmetry is what keeps verification overhead below 0.1%. > [!NOTE] Beyond this description > Additional layers of security harden the scheme; the process above is the > dominant term in the validation cost equation. ## Penalties come out of work credit Validation runs as a parallel, ongoing process against a pool of submitted logits. It does not block transaction processing, but invalid work, when detected, results in retrospective slashing of work credit. That credit is called LStake ("logit stake"): a measure of a node's validated problem-solving contribution over the short and medium term rather than a locked token stake. It takes the place token stake holds in other designs. Leader election and rewards flow from validated useful work performed, and cheating destroys that accumulated standing. ## Status on the live network The on-chain auction program that carries verification state is active on the testnet, and the API accepts verification-related request flags, but verification artifacts are not yet returned to API callers. ## Keep reading - [Network architecture](https://ambient.xyz/docs/learn/architecture) shows where PoL sits in the request lifecycle. - [What is Ambient?](https://ambient.xyz/docs/learn/what-is-ambient) covers the wider thesis. --- # Network architecture > The roles that make up the Ambient network (users, the gateway layer, miners, validators) and how a request flows from auction to settlement. - Canonical: https://ambient.xyz/docs/learn/architecture --- Four roles make up the Ambient network: users and agents, the gateway layer, miners, and validators. A single inference request passes through all of them on its way from auction to settlement. The two diagrams below give the shape at a glance: a single node's internal layers, then the life of a request across nodes; the sections that follow explain each piece. [Diagram: Layer table titled Ambient Node Architecture. Four component groups, each with its subcomponents. APIs and SDKs: Language SDKs, RESTful Services. Blockchain Infrastructure: Smart Contracts, Consensus Processing, Transaction Services. AI Model Training and Execution Engine: Model Profiler, Sharding Manager. Network Services: Data Oracles, Query Processing, Privacy Primitives.] *A single Ambient node's internal layers (“Ambient Node Architecture”): APIs and SDKs, blockchain infrastructure, the AI model training and execution engine, and network services.* [Diagram: Flow graph laid out as three bands. Serving a query: User Queries and Contract Queries feed the Query Auction: listings include fee tokens for escrow, timing requirements, and validation requirements (if beyond minimum), input text size, etc. Mining Clusters place bids into the Query Auction (bids refundable on successful completion) and produce Unvalidated Query Results. Validation: Validator Cluster B (query result validators chosen in a weighted random fashion based on LStake) points at the Unvalidated Query Results, which become Validated Query Results and accrue LStake to successful problem solvers; Validator Cluster A performs LStake weighted voting on correctness of new state. Advancing the chain: Node A and Node B emit PoH sequences to the Leader, which performs transaction ordering based on PoH sequences; the Leader and Validator Cluster A point at New State, which produces a New Block.] *Continuous Proof of Logits (cPoL) in Action, where LStake = “Logit Stake,” a shorthand for measured relative problem solving contribution.* ## The four roles - **Users and agents.** Anyone submitting an inference request: a person in the [Ambient app](https://app.ambient.xyz), an application calling the API, or an on-chain agent. Requests state what the caller wants served, within what time, and at what price. - **The gateway layer.** The web and API layer at `api.ambient.xyz` accepts OpenAI- and Anthropic-compatible requests and routes them into the network. This layer also handles query intake; the auction process is designed to obfuscate the origin of queries and the consumers of results (see Privacy below). - **Miners.** GPU operators who run the network model. They bid on queries, perform the actual inference, and commit [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits) hashes as they generate. Mining is the expensive side of the work asymmetry. - **Validators.** Nodes that spot-check miner output by re-running a small sample of its tokens and comparing logit hashes. Validators are chosen in a weighted random fashion based on LStake, their own record of validated useful work. Validation is the cheap side of the asymmetry, and it runs in parallel without blocking transaction processing. Roles are not exclusive. The consensus design lets nodes specialize (some on LLM operations, some on transaction processing, some on validation), with all of them rewarded relative to validated contribution. ## Life of a request A single inference request moves from auction to settlement in four stages. Validation is retrospective and parallel; it never sits between you and your response. ### 1. Auction Queries enter the system through an auction contract. The user or agent declares, in effect: "I would like this query served within X minutes, and I am willing to pay Y." Miners bid on the query; a miner's bid is refunded when it completes the query within the specified time, which is what gives the network its quality-of-service teeth. On the testnet chain, this is a native on-chain (SBF) program: the Ambient auction program. It creates a `JobRequest` account for the request, carrying the request's bundle, price and output-token ceilings, context-length and expiry tiers, and an IPFS content identifier for the input data. IPFS holds the input data as temporary storage in the auction mechanism. ### 2. Inference The winning miner runs the request on the network model. As generation proceeds, the miner produces the per-token logit hashes and progress markers described in [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits). The request's on-chain status moves from `WaitingForOutput` to `OutputReceived`. ### 3. Verification The auction program tracks a verification state for every job: a Merkle root of the output data, the set of assigned validators (the auction program calls them verifiers), and the token ranges each validator is responsible for. Assigned validators re-run their sampled tokens and check the miner's committed hashes. Each sampled check costs a single token of inference against the thousands the miner generated, so verification adds less than 0.1% overhead. ### 4. Settlement When validators confirm the output, the request reaches `OutputVerified` and the job settles: the miner's timely completion is honored under the auction terms, and the validated work is credited to the miner's and validators' LStake, the work-credit measure that drives leader election and rewards. Invalid work, when detected, results in retrospective slashing of that work credit. ## Consensus underneath Ambient pairs Proof of Logits with the Proof of History architecture described in the Solana whitepaper, replacing Solana's proof of stake with Ambient's proof of useful work. Leaders are elected on a weighted average of short- and medium-term validated contributions, and elected leaders process and order transactions continuously. Because logit validation is decoupled from transaction processing, consensus stays non-blocking. > [!NOTE] Design vs. deployment > The consensus scheme is a specification. The chain runs as a testnet > with the on-chain auction program active. ## What a node exposes In the designed node architecture, every node presents the same surfaces. Clients reach its subsystems over simple RESTful services and through language-specific SDKs; the initial SDK targets are JavaScript, Python, Go, and Rust. Smart contracts execute in Ambient's fork of the SVM, with extensions to the SDK for calling the on-network foundation model and for agentic tooling. A model profiler produces the fingerprints validators use for both inference and training, and network service primitives handle anonymized query processing and data access. ## Scaling to a very large model Running and training a 600B+ model across independent nodes is only tractable with aggressive sharding. The design draws on two lines of research: PETALS (distributed inference and fault tolerance across unreliable, geographically dispersed devices) and Distributed SLIDE (adaptive dropout and hash-based sparse computation for low-bandwidth, few-core clusters). Four techniques carry the load: - **Sparsity.** Adaptive dropout and hash-based neuron selection cut the computation and cross-node communication each training step requires. - **Model parallelism.** The model and its hash tables are sharded across nodes, with fault-tolerance mechanisms that absorb node failures dynamically. - **Distributed computing under constraints.** Adaptive sparsity limits the data that must synchronize across the network, and load balancing spreads work across heterogeneous, unreliable hardware. - **Algorithmic over hardware acceleration.** The goal is competitive performance for a state-of-the-art model on relatively low-spec hardware, favoring smart algorithms over raw acceleration. The intent is to lower the hardware bar for participation so mining is not confined to the largest operators. ## Privacy Making both transactions and inference anonymous and censorship-resistant is a core design goal, approached with a range of techniques. The simplest is client-side obfuscation of personally identifiable data using a small local LLM before a request leaves the caller. The query auction is designed to obfuscate the origin of queries and the consumers of results. The most complex technique, pending a performant implementation, is fully or somewhat homomorphic encryption. Pre-training data is not obfuscated, but generated synthetic data can obscure fine-tuning data. ## Data availability Training moves very large volumes of data, and ordinary economic incentives are weak at preserving that much data for long enough to keep model training reproducible. The design addresses this by integrating both HTTP and BitTorrent oracles directly into the nodes, with IPFS as temporary storage within the auction mechanism. ## Evolving the network model The network model is meant to stay evergreen. A proposed voting system would let participants initiate new training campaigns that are specified programmatically: a training run can be proposed fully in code, referencing web and torrent URLs for its data, and is then interleaved with ordinary inference workloads across the network. ## Keep reading - [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits) covers the verification mechanism in detail. - [Tokenomics](https://ambient.xyz/docs/learn/tokenomics) explains how reward design follows from work credit. --- # Testnet > The live Ambient testnet (external services, the on-chain Ambient Main Program, and the off-chain miner/validator components) plus how developers, miners, and validators take part. - Canonical: https://ambient.xyz/docs/learn/testnet --- The testnet is live. Developers send queries through the API service or a chat demo, miners bid on and serve them, and validators audit the results. ## High-level testnet architecture The testnet architecture includes an on-chain program, off-chain miners/validators and external services. [Diagram: High-level Ambient testnet architecture. External services: the Web reaches an API Service FE, which calls the API Service, and a Chat Demo; all of them feed the Web2 APIs layer, which forwards requests to the auction app, which submits them to an RPC Node. On chain: the RPC Node drives the Ambient Main Program, which buckets and bundles requests, creates an auction for each bundle, selects the auction winner, selects validators and their validation ranges, collects validation results, and tracks success or failure on chain. Off-chain miners: each GPU Miner/Validator runs an RPC/Validator service that listens for auctions, places bids, closes auctions and listens for winning bids, manages query data transfer, listens for validation selection, writes results on chain, manages validation data transfer, and manages the vLLM cluster; that service drives a vLLM instance which returns generated tokens. Request data flows from the chain to the miners and response data flows back. Other miners participate in the same auctions and validation.] *High-level testnet architecture: external services hand requests to the auction app and RPC node, the on-chain Ambient Main Program bundles and auctions them, and GPU miner/validator nodes serve the inference on vLLM.* ### External services - **Web/API layer:** Public users interact through an **API service front-end** or a chat demo. The API service proxies requests to **Web2 APIs** (such as HTTP or existing AI services) and forwards valid requests to the Ambient network. - **Auction app:** The auction app submits requests to an **RPC node**, which interacts with the on-chain program. ### On-chain program (Ambient Main Program) The **Ambient Main Program** runs on the Solana-compatible chain and manages core logic: - **Bucket & bundle requests:** it groups individual queries into bundles to improve throughput. - **Auction creation and winner selection:** the program creates auctions for each bundle, receives bids from miners and selects winners. The litepaper explains that queries enter the system via an **auction contract** where users specify a maximum time and payment; miners bid, and refunds are issued if miners complete the query within the time limit. Validators are chosen randomly based on **Logit Stake (LStake)**. - **Validator selection and validation ranges:** for each bundle, the program assigns validators and defines the token ranges they must validate. - **Result collection and tracking:** the program collects validation results and records success or failure on-chain, ensuring that miners are compensated only when results are correct and timely. ### Off-chain components - **RPC node:** Bridges the on-chain program with miners. It sends auction events to miners, receives bids, and forwards results back to the chain. - **GPU miner/validator:** Each miner runs an **RPC/validator service** and a **vLLM** instance (a high-performance LLM runtime). The miner: - Listens for auctions and places bids. - Retrieves bundled queries and performs inference using the network's LLM. - Produces hashed logits and submits partial results to the chain for PoL verification. - Listens for validation assignments and recomputes selected tokens to verify other miners' results, writing validation data on-chain. - Manages the vLLM cluster (loading the foundation model and scaling inference across GPUs). - **Other miners:** Compete in auctions and perform inference/validation just like the primary miner. Competition for auctions incentivizes low latency and efficient computation. ## Workflow example ### 1. User query submission A developer or agent sends a request via the API service, specifying constraints such as maximum response time and the amount they are willing to pay. Queries are grouped into bundles by the auction app. ### 2. Auction and bidding The on-chain program announces an auction for a bundle. Miners listen for auctions and place bids. Miners whose bids win commit to delivering the results within the agreed time. According to the litepaper, miners' bids are refunded if they complete the query within the specified period. ### 3. Inference and result submission The winning miner runs the query on its vLLM instance, generates hashed logits for each token and submits the output and PoL hashes to the chain. Validators are randomly selected based on their logit stake to audit the result. ### 4. Validation Validators recompute a small portion of the query (a randomly selected token) using the same context and model. If the hashed logits match, the result is accepted. This process ensures that validation is inexpensive (only one token of inference) compared with the original computation. ### 5. Settlement and reward When results are accepted, the miner receives compensation (transaction + inflation-based) and the user's payment is released. If the miner fails to deliver on time or produces incorrect results, they forfeit their bond and the query is re-auctioned. ## Participating in the testnet - **Developers/users:** To try the testnet, developers call the API service or chat demo with their queries. They can specify maximum response times and payment amounts. The network accepts HTTP and BitTorrent data sources via integrated oracles. - **Miners:** Potential miners should provision GPUs and run the Ambient miner software, which includes an RPC/validator component and a vLLM runtime. Miners need to listen for auctions, place competitive bids, execute inference tasks, and participate in validation. Because the network focuses on a single open-weights model, miners can optimize their hardware for predictable workloads. Onboarding today runs in curated waves on datacenter-class hardware. See [Run a node](https://ambient.xyz/docs/mine) for what a wave requires. - **Validators:** Validators typically run alongside miners. They should maintain synchronization with the blockchain, store the foundation model (or relevant shards) and be prepared to re-compute small portions of other miners' outputs. Validators are selected based on their logit stake and receive rewards for successful validations. > [!WARNING] Testnet conditions > During the testnet phase, expect limited throughput and experimental > changes as auction parameters and validation ranges are optimized. ## Keep reading - [Network architecture](https://ambient.xyz/docs/learn/architecture) covers the four network roles and the life of a request from auction to settlement. - [Run a node](https://ambient.xyz/docs/mine) covers hardware requirements and miner onboarding. --- # Tokenomics > How Ambient rewards validated useful work. Work credit, work-weighted leader election, and auction pricing. - Canonical: https://ambient.xyz/docs/learn/tokenomics --- Ambient's network economics have a defined shape but no committed numbers. > [!WARNING] Coming soon > Ambient's token economics have **not been announced**. There is no > published ticker, total supply, allocation, emission schedule, fee > model, or burn mechanism. Official token details will be published here > and through Ambient's own channels. ## The reward design, qualitatively The incentive design rests on work credit: - **Rewards follow validated useful work.** Nodes earn credit, called LStake ("logit stake"), for contributions of valid proofs of work: inference, fine-tuning, and training, tracked over the short term (days) and medium term (months). LStake is a measured contribution, not a locked token bond. - **Leader election is work-weighted.** Leaders are elected based on a weighted average of their short- and medium-term validated proofs of work, and nodes are rewarded for contributions to the logit pool, successful leader terms, and participation in finality voting. - **Penalties are retrospective work-credit slashing.** Ongoing validation can detect invalid work after the fact and slash the offender's accumulated work credit. The design does not rely on slashing a locked token stake. - **Pricing is set by auction.** Users and agents declare a price and a latency target; miners bid to serve it, each posting a deposit that is returned on on-time completion and forfeited if they miss. The intent is proof-of-work economics: miner rewards that favor active contribution over incumbency, so new compute always has a reason to join. ## Keep reading - [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits) explains where work credit comes from. - [Network architecture](https://ambient.xyz/docs/learn/architecture) covers the auction that prices requests. --- # Use Ambient > What you can use today. The web app at app.ambient.xyz for chat, research, keys, and billing, plus Ambient Desktop. - Canonical: https://ambient.xyz/docs/use --- Ambient's user-facing products are the web app at [app.ambient.xyz](https://app.ambient.xyz) and the Ambient Desktop application. ## The web app Sign in at [app.ambient.xyz](https://app.ambient.xyz). The sidebar gives you chat plus the account surfaces: API Keys, Usage, Team, Drops, Billing, Docs, and Support. ### Chat, Thinking, and Research **New Chat** opens a conversation with the network model; the input is labeled "Ask Ambient…". A drop-down next to the chat header switches modes. **Chat** gives instant conversational responses. **Thinking** takes longer and aims for more considered answers. **Research** engages wider retrieval and returns detailed, citation-rich responses; use it for literature reviews and background reports. ### API keys The **API Keys** page shows the API base URL and lets you create keys. Each key is a secret: treat it like a password, create separate keys per project, and replace any key that leaks. The page includes cURL, JavaScript, and Python snippets ready to copy. From there, head to [Get started](https://ambient.xyz/docs/get-started) to make your first request. ### Usage, teams, and Drops **Usage** charts prompt tokens, completion tokens, and request counts, filterable by timeframe and per key. **Team** manages members, roles, and invitations; you can run multiple teams and switch between them. **Drops** issues testnet tokens for experimentation. They have no monetary value and cannot be traded or withdrawn. ### Billing and credits The **Billing** page shows your available credits and current token pricing. Purchase credits to fund API usage; auto-top-up, where available, buys more when your balance runs low. ## Ambient Desktop Ambient Desktop is a local-first agentic workstation for macOS, Windows, and Linux, open source under MIT and currently in Developer Preview. Agents operate on your real files, terminals, and source control; every action surfaces evidence you can inspect, and inference comes from the Ambient network. Start with the [Ambient Desktop overview](https://ambient.xyz/docs/use/desktop), then [Install Ambient Desktop](https://ambient.xyz/docs/use/desktop/installation) for downloads and per-platform install caveats, and the [quickstart](https://ambient.xyz/docs/use/desktop/quickstart) for the first-run Welcome Folder flow. After that, move on to the feature surfaces: - [Project Board](https://ambient.xyz/docs/use/desktop/project-board): goals become durable plans, task cards, and review loops - [Durable goals](https://ambient.xyz/docs/use/desktop/durable-goals): long-running work that survives restarts - [Symphony](https://ambient.xyz/docs/use/desktop/symphony): parent/child agent orchestration (in development) - [Workflow Recorder](https://ambient.xyz/docs/use/desktop/workflow-recorder): record a task once, re-run it as a callable workflow (in development) - [Provider routing](https://ambient.xyz/docs/use/desktop/provider-routing): preference-ordered providers with visible fallback evidence - [Remote control](https://ambient.xyz/docs/use/desktop/remote-control): drive a running desktop from Telegram, approval-gated ## Keep going - [Get started](https://ambient.xyz/docs/get-started) shows how to call the API with your new key. - [Learn](https://ambient.xyz/docs/learn) explains how verification works under the hood. --- # Ambient web app > The three surfaces of the Ambient web app. Chat for conversation, Research for citation-rich analysis, and API Keys for integrating Ambient into your own code. - Canonical: https://ambient.xyz/docs/use/app --- The Ambient web app has three surfaces: **Chat**, **Research**, and **API Keys**. ## Chat The default experience in Ambient is a simple chat interface labelled **Ask Ambient**. Use it to have conversations with Ambient's AI and receive instant responses. 1. **Start a new chat**: When you log in, you'll see a menu on the left. Select **New Chat** to open a blank conversation window. 2. **Type your question**: Click in the blue input box labelled "Ask Ambient…" at the bottom of the main panel and enter your query. Ambient's model is capable of natural-language tasks such as answering questions, summarizing articles or drafting short emails. 3. **Send the message**: Press the send arrow to submit your prompt. The AI will respond in the chat area. You can continue the conversation by entering follow-up questions. Ambient also offers a **Thinking** mode that takes more time to generate higher-quality answers. Use the drop-down next to the chat title to switch modes. ## Research Research mode is designed for deeper, citation-rich analysis. It uses the same underlying model but engages additional retrieval capabilities to provide more detailed answers and references. 1. **Select Research mode**: In the chat header, click the drop-down arrow and choose **Research**. The header will change to **Research with Ambient**, and the input box will indicate research mode. 2. **Enter your research query**: Type your topic or question. Ambient will perform a broad search, synthesize information and return a detailed response with citations when available. 3. **Review citations and continue**: Responses may include references to support the information. You can ask follow-up questions or request clarification in the same thread. ## API keys Developers can integrate Ambient into their own applications using the Web2 API. To do so, you'll need to create an API key. 1. **Navigate to API Keys**: From the sidebar menu, select **API Keys**. You'll see the **Web2 API URL** and a **Keys** section. 2. **Create a key**: Click the **Create Key** button in the **Keys** section. Ambient will generate a secret key. 3. **Use the key in your code**: The page shows example snippets for cURL, JavaScript and Python. Replace `[YOUR_API_KEY]` in the sample code with your actual key. You can then call Ambient's chat/completions endpoint at the Web2 API URL to get model responses. 4. **Manage keys**: If a key is compromised, delete it and create a new one. There is no limit to the number of keys you can generate, but creating separate keys for different projects makes them easier to manage. > [!WARNING] Important > Treat this key like a password. Do not share it publicly. ## Keep going - [Using the web app](https://ambient.xyz/docs/get-started/web-app) walks through sign-in, usage, teams, Drops, and billing end to end. - [Ambient Desktop](https://ambient.xyz/docs/use/desktop) is the local-first agentic workstation, for work that needs your real files and terminals. --- # Ambient Desktop > The open agentic workstation. A local-first agentic workstation, model-orchestration engine, and miner that runs capable agents on your real machine instead of a quarantined VM. - Canonical: https://ambient.xyz/docs/use/desktop --- Ambient Desktop is the open agentic workstation: a local-first agentic workstation, model-orchestration engine, and miner. Run capable agents on your own machine, not a quarantined VM, with curated plugins, sandboxed capabilities, and inference from a credibly neutral, zero-data-retention network. Open source (MIT) · runs locally on macOS, Windows, and Linux · ships with GLM 5.2 · v0.1.97 · Developer Preview. - [Run the Quickstart](https://ambient.xyz/docs/use/desktop/quickstart) - [Download for your OS](https://ambient.xyz/docs/use/desktop/installation) - [View the source (MIT)](https://github.com/ambient-xyz/AmbientDesktop) The shell itself combines chat, workspace context, navigation, and evidence panels in one local developer workstation: chat, sidebar, and workspace controls in a single window. ## A workstation, not a chat wrapper Most agent tools hand you a chat box and a transcript. Ambient Desktop hands you a workspace. Agents operate on your real files, terminals, browsers, and source control, and every move shows up as something you can open and judge: a plan, a board card, an artifact, a screenshot, a validation command, a Git diff. And it runs **on your real machine**, not a quarantined VM, because a security model that contains the risky capabilities instead of the whole agent means you do not have to choose between capable and safe. You stay the reviewer: pause, inspect the evidence behind any result, correct course, and resume without the agent losing the thread. ## What makes Ambient different These are what separate Ambient from a coding copilot or a single-prompt agent. Each one exists because long-running, autonomous work needs structure, memory, and boundaries. ### Project Board **Durable, visible work.** Large or ambiguous requests become a Kanban of source-backed cards with evidence, dependencies, and a review loop, not a transcript you have to scroll. [Explore the Project Board](https://ambient.xyz/docs/use/desktop/project-board). ### Durable goals **Survives restarts.** Long-running goals persist their plan, evidence, and continuation state to disk, so work resumes from saved state instead of restarting from memory. [How durable goals work](https://ambient.xyz/docs/use/desktop/durable-goals). ### Symphony orchestration **More than one agent.** A parent session delegates scoped work to specialist children (research, implementation, review, local-model) with budgets, approvals, and an artifact-driven join. [See Symphony](https://ambient.xyz/docs/use/desktop/symphony). ### Contained capabilities **Sandboxed by default.** Risky tools (MCP servers, scrapers, Pi packages) run behind ToolHive containers and permission policy, so the agent can work on a normal desktop without blind trust. [Read the security model](https://ambient.xyz/docs/use/desktop/security). ### Provider routing **You pick the path.** Search, fetch, browser, vision, local, and cloud providers are ordered by your preference and task fit, with visible fallback evidence when one is skipped. [Provider routing](https://ambient.xyz/docs/use/desktop/provider-routing). ### Workflow Recorder **Repeatable by design.** Record a successful research or ops task once, then generalize it into a parameterized, callable workflow that runs like a reviewed tool. [Record a workflow](https://ambient.xyz/docs/use/desktop/workflow-recorder). ### Open and yours **Open by default.** MIT-licensed harness, local-first, zero-data-retention inference. The code is open, your files stay on your machine, and the API keeps nothing. Bring your own models or use the network's. [API and endpoints](https://ambient.xyz/docs/use/desktop/api-endpoints). ## Frontier model, included Ambient ships with GLM 5.2, included and served from a credibly neutral, zero-data-retention network. Use it as your main agent and for sub-agents. | Model | Role | What it is | | --- | --- | --- | | GLM 5.2 | Default | The default model for Ambient Desktop (`z-ai/glm-5.2`), fast and capable, tuned for agentic coding and tool use. | Kimi K2.7 Code (`moonshotai/kimi-k2.7-code`), previously offered as an alternative, has been retired from the network and is no longer available. Prefer your own tooling? The same model is available through Ambient's OpenAI-compatible API. See [API and endpoints](https://ambient.xyz/docs/use/desktop/api-endpoints) for the desktop's local endpoints, or the [Ambient API quickstart](https://ambient.xyz/docs/get-started/quickstart) for the network API. ## Get started in three steps ### 1. Install the app Download the signed build for macOS, Windows, or Linux, or build from source. First launch runs health checks for providers and runtimes. [Installation guide](https://ambient.xyz/docs/use/desktop/installation). ### 2. Follow the Welcome Folder A pinned first-run project walks you through the shell, Core Setup, and Plugin Setup using the real product surfaces, not a sample repo. [Open the Quickstart](https://ambient.xyz/docs/use/desktop/quickstart). ### 3. Run your first task Build a small calculator three ways (direct prompt, Planner-to-goal, and Planner-to-board) and inspect the proof behind each result. [Three task paths](https://ambient.xyz/docs/use/desktop/quickstart#run-a-calculator-task-three-ways). ## Where the product is going Coding is the first high-value application because it exercises every hard part of agentic systems. But the destination is bigger: Ambient Desktop is the local front door to a network building **intelligence as a global utility**: a model-orchestration engine, a blockchain client, and the miner for the upcoming open season of Testnet mining. Below are the four surfaces and the routing fabric that ties them together; the [product north star](https://ambient.xyz/docs/use/desktop/north-star) covers the same arc in detail, including how local models, network calls, plugins, and programs resolve into one routing fabric. Ambient Desktop starts with high-value developer work and grows into the official workstation for the Ambient Network. [Diagram: Ambient Desktop North Star diagram. The Ambient Desktop hub grows into the official workstation for the Ambient Network across four surfaces: Agentic Desktop (coding, workflows, browser evidence; Project Board and durable goals; stable tools plus preview workflows), Ambient Network Client (wallet, balances, programs; Tool Oracle and x402 direction; first-party blockchain workbench), Ambient Mini Miner (opt-in local model mining; llama.cpp runtime foundation; earn network rewards), and Curated Capability Storefront (reviewed Web2/Web3 capabilities; MCP, CLI, and Pi packages; permissioned install paths), all on one Vertically Integrated Routing Fabric spanning local models, Ambient cloud, Ambient Mini, plugins, browser providers, and network operations.] *Ambient Desktop North Star: Ambient Desktop starts with high-value developer work and grows into the official workstation for the Ambient Network.* ### Agentic Desktop **Developer Preview.** The local-first coding and workflow surface: Project Board, durable goals, browser evidence, Git review, and artifact previews. This is what ships today. ### Ambient Network Client **In development.** The first-party client for embedded key flow, balances, programs, transaction evidence, [Tool Oracle](https://ambient.xyz/docs/build/tool-oracle), and [x402](https://ambient.xyz/docs/build/x402), in active development. See [Network client](https://ambient.xyz/docs/use/desktop/network-client). ### Ambient Mini Miner **Roadmap.** An opt-in surface to host a local model, mark a machine as mineable, and earn network rewards when eligible. On the roadmap, built on today's llama.cpp runtime. See [Mini Miner](https://ambient.xyz/docs/mine/mini-miner). ### Curated Capability Storefront **Roadmap.** A reviewed marketplace for Ambient-compatible Web2 and Web3 capabilities: MCP servers, CLI packages, Pi tools, and workflow artifacts. See [Plugins and marketplace](https://ambient.xyz/docs/use/desktop/plugins). ## Honest about maturity Every page carries an explicit label (Available, Developer Preview, In Development, or Roadmap) so you always know what to rely on, what to test, and where implementation is still moving. These are operational signals, not marketing tiers. See [Maturity labels](https://ambient.xyz/docs/resources/maturity-labels) for what each label means. ## Run agents you can trust To run agents on your own machine with inference that keeps nothing, start with the [Quickstart](https://ambient.xyz/docs/use/desktop/quickstart), or [download Ambient Desktop](https://ambient.xyz/docs/use/desktop/installation) for your platform. ## Keep going - [Quickstart](https://ambient.xyz/docs/use/desktop/quickstart): start in the Welcome Folder, finish setup, then run a small calculator task with visible proof. - [Project Board](https://ambient.xyz/docs/use/desktop/project-board): turns goals into durable plans, task cards, source-backed evidence, and review loops. - [Security model](https://ambient.xyz/docs/use/desktop/security): most agent tools protect you by sandboxing the whole agent, which also blinds it. Ambient does the opposite: the agent works on your real desktop, while the genuinely risky capabilities are the things that get contained. --- # Product north star > The candid product thesis. Ambient Desktop becomes the workstation for agentic work on the Ambient Network, with coding as the first high-value application and four product surfaces on the path there. - Canonical: https://ambient.xyz/docs/use/desktop/north-star --- The candid product thesis: Ambient Desktop becomes the workstation for agentic work on the Ambient Network. It starts with high-value developer work and grows into the official workstation for the Ambient Network. [Diagram: Ambient Desktop North Star diagram. The Ambient Desktop hub grows into the official workstation for the Ambient Network across four surfaces: Agentic Desktop (coding, workflows, browser evidence; Project Board and durable goals; stable tools plus preview workflows), Ambient Network Client (wallet, balances, programs; Tool Oracle and x402 direction; first-party blockchain workbench), Ambient Mini Miner (opt-in local model mining; llama.cpp runtime foundation; earn network rewards), and Curated Capability Storefront (reviewed Web2/Web3 capabilities; MCP, CLI, and Pi packages; permissioned install paths), all on one Vertically Integrated Routing Fabric spanning local models, Ambient cloud, Ambient Mini, plugins, browser providers, and network operations.] *Ambient Desktop North Star: Ambient Desktop starts with high-value developer work and grows into the official workstation for the Ambient Network.* The four surfaces below sit at different points on that arc: | Surface | State | | --- | --- | | Agentic Desktop | Current and preview | | Ambient Network Client | In development | | Ambient Mini Miner | Roadmap | | Curated Capability Storefront | Marketplace direction | All four are surfaced through the same shell, which combines chat, workspace context, navigation, and evidence panels: chat, sidebar, and workspace controls in a single window. ## The thesis Ambient Desktop is not only a coding agent. Coding is the first high-value application because it proves local agency, permissions, tools, browser evidence, artifact review, and workflow UX. The same primitives become the workstation for Ambient Network operations. A developer should be able to move from code work to network work without changing mental models: inspect state, authorize capability use, capture evidence, route through the right provider, and preserve a durable record of what happened. ## Four product surfaces ### Agentic Desktop Current and preview surfaces for coding, workflows, [Project Board](https://ambient.xyz/docs/use/desktop/project-board), browser evidence, Git review, and local artifact inspection. ### Ambient Network Client The in-development first-party path for balances, embedded key flow, programs, transaction observation, Ambient L1 CLI integration, [Tool Oracle](https://ambient.xyz/docs/build/tool-oracle), and [x402](https://ambient.xyz/docs/build/x402) workflows. See [Network client](https://ambient.xyz/docs/use/desktop/network-client) for what exists in the app today. ### Ambient Mini Miner The roadmap mining surface for opt-in local Ambient Mini hosting, mineable machine state, routing eligibility, receipts, and network rewards. See [Mini Miner](https://ambient.xyz/docs/mine/mini-miner). ### Curated Capability Storefront The marketplace direction for reviewed Web2/Web3 technologies built on Ambient: MCPs, CLI packages, Pi tools, local runtimes, and finalized workflow artifacts. See [Plugins and marketplace](https://ambient.xyz/docs/use/desktop/plugins). ## The routing fabric The critical product idea is vertical integration. Ambient Desktop does not treat local models, cloud models, plugins, browser providers, and network programs as isolated settings. They become a routing fabric that can choose the right capability for a task, fall back when needed, and preserve evidence of each decision. - Local models provide privacy, latency, and opt-in mining foundations. - Ambient provider calls provide high-capability reasoning and network-native behavior. - Ambient Mini adds a local model network layer where eligible machines can earn network rewards. - Curated plugins and CLI packages turn external services into permissioned capabilities. - Project Board and workflow artifacts make the routing decisions visible to developers. ## Maturity discipline This north star includes available product paths, developer-preview surfaces, in-development integrations, and roadmap commitments. The documentation labels those states explicitly so contributors know which pieces can be relied on today and which pieces still require implementation work. See [Maturity labels](https://ambient.xyz/docs/resources/maturity-labels) for what each label means. ## Keep going - [Ambient Desktop](https://ambient.xyz/docs/use/desktop): what the app is today (install, first session, and the shipped feature surfaces). - [What is Ambient](https://ambient.xyz/docs/learn/what-is-ambient): the network the workstation is being built onto. - [Network client](https://ambient.xyz/docs/use/desktop/network-client): the same workstation that runs your code is growing into a first-party client for the Ambient Network: embedded keys, balances, programs, and transaction evidence, with the same inspect-everything posture as the rest of the app. This surface is in active development. - [Mini Miner](https://ambient.xyz/docs/mine/mini-miner): if your machine is already running local models, it could do useful work for the network when you are not. Ambient Mini mining is a planned, opt-in way to host a local model and earn network rewards when eligible. - [Plugins and marketplace](https://ambient.xyz/docs/use/desktop/plugins): Ambient extends through plugins and capabilities, but every install has a visible class, permission profile, and uninstall path. The marketplace direction is curated and legible, not a raw feed of arbitrary executable code. --- # Install Ambient Desktop > Install Ambient Desktop from packaged artifacts on macOS, Windows, and Linux, run the per-capability health checks after first launch, or build it from source. - Canonical: https://ambient.xyz/docs/use/desktop/installation --- Install Ambient Desktop from packaged artifacts or build it from source on macOS, Windows, and Linux. Use the packaged installers for normal use, and source builds for development, debugging, and platform packaging validation. Once it is installed, run the [quickstart](https://ambient.xyz/docs/use/desktop/quickstart). ## Choose the right path Most users should install the packaged app from the stable update channel. Developers working on Ambient Desktop itself should build from source when they need local code changes, debug symbols, or platform-specific packaging validation. The current stable channel is version 0.1.97. Prefer versioned URLs when documenting a reproducible setup and latest aliases when a user simply wants the newest stable artifact. ### macOS Apple Silicon Use the signed and notarized DMG for normal installation. The ZIP is useful for update testing and artifact inspection. - Latest DMG: [ambient-desktop-latest-mac-arm64.dmg](https://updates.ambient.xyz/desktop/stable/ambient-desktop-latest-mac-arm64.dmg) - Latest ZIP: [ambient-desktop-latest-mac-arm64.zip](https://updates.ambient.xyz/desktop/stable/ambient-desktop-latest-mac-arm64.zip) - Versioned DMG: [Ambient%20Desktop-0.1.97-mac-arm64.dmg](https://updates.ambient.xyz/desktop/stable/Ambient%20Desktop-0.1.97-mac-arm64.dmg) - Versioned ZIP: [Ambient%20Desktop-0.1.97-mac-arm64.zip](https://updates.ambient.xyz/desktop/stable/Ambient%20Desktop-0.1.97-mac-arm64.zip) ### Windows x64 Use the NSIS installer for normal installation. The Windows artifact exists, but early builds may show SmartScreen or reputation prompts until Authenticode signing and installer reputation mature. - Latest installer: [ambient-desktop-latest-win-x64.exe](https://updates.ambient.xyz/desktop/stable/ambient-desktop-latest-win-x64.exe) - Latest ZIP: [ambient-desktop-latest-win-x64.zip](https://updates.ambient.xyz/desktop/stable/ambient-desktop-latest-win-x64.zip) - Versioned installer: [Ambient%20Desktop-0.1.97-win-x64.exe](https://updates.ambient.xyz/desktop/stable/Ambient%20Desktop-0.1.97-win-x64.exe) - Versioned ZIP: [Ambient%20Desktop-0.1.97-win-x64.zip](https://updates.ambient.xyz/desktop/stable/Ambient%20Desktop-0.1.97-win-x64.zip) ### Linux x64 Use the AppImage for a portable install or the deb package for Debian/Ubuntu style desktops. Linux package signing is still a release hardening item. - Latest AppImage: [ambient-desktop-latest-linux-x86_64.AppImage](https://updates.ambient.xyz/desktop/stable/ambient-desktop-latest-linux-x86_64.AppImage) - Latest deb: [ambient-desktop-latest-linux-amd64.deb](https://updates.ambient.xyz/desktop/stable/ambient-desktop-latest-linux-amd64.deb) - Versioned AppImage: [Ambient%20Desktop-0.1.97-linux-x86_64.AppImage](https://updates.ambient.xyz/desktop/stable/Ambient%20Desktop-0.1.97-linux-x86_64.AppImage) - Versioned deb: [Ambient%20Desktop-0.1.97-linux-amd64.deb](https://updates.ambient.xyz/desktop/stable/Ambient%20Desktop-0.1.97-linux-amd64.deb) ### Verify before trust Use release.json and SHA256SUMS to verify artifact names, sizes, and hashes when installing into a development or release-validation environment. - Manifest: [release.json](https://updates.ambient.xyz/desktop/stable/release.json) - Checksums: [SHA256SUMS](https://updates.ambient.xyz/desktop/stable/SHA256SUMS) ## Packaged install: macOS macOS is the most straightforward packaged path today. The DMG is the recommended install artifact for Apple Silicon machines. ### 1. Download the DMG Use the latest DMG for normal use or the versioned 0.1.97 DMG when reproducing a specific release. ### 2. Open the disk image and drag Ambient Desktop into Applications Launch from Applications rather than directly from the mounted disk image so user data, updates, and OS permissions behave normally. ### 3. Approve normal macOS prompts The app may request access needed for local development workflows such as files, terminal sessions, browser automation, or notifications. Grant only the permissions required for the workflow you are testing. ### 4. Verify first launch Open Settings and confirm provider configuration, local runtime status, browser capability status, and plugin/capability health checks before running high-impact tasks. ## Packaged install: Windows Windows packaging is active and published on the stable channel. The important difference is trust UX: until Windows signing and reputation are fully established, users may see SmartScreen, Windows Defender Firewall, or installer reputation prompts. > [!WARNING] Expect trust prompts on Windows > Those prompts are part of installation, not an unexpected failure. > Developers validating Windows should record which prompt appeared, which > artifact was used, and whether the installed app launched from a normal > user path. ### 1. Download the x64 installer Use the latest or versioned NSIS installer from the stable channel. Keep the ZIP for artifact inspection or manual unpack testing. ### 2. Handle SmartScreen or reputation warnings deliberately If Windows reports that the app is unrecognized, verify the artifact URL and SHA-256 first. Only proceed when the artifact matches the published stable manifest. ### 3. Install for the current user Accept the installer prompts and launch Ambient Desktop from the Start Menu or desktop shortcut rather than directly from a temporary downloads directory. ### 4. Review firewall prompts Local runtime servers, browser bridges, or model hosting may trigger Windows Defender Firewall prompts. Allow only the network scopes required by the workflow; most local runtime flows should stay on localhost. ### 5. Run first-launch checks Confirm the app opens, Settings loads, terminal/runtime checks run, and any Windows-specific blocked capabilities are clearly labeled rather than silently failing. ## Packaged install: Linux Linux supports a portable AppImage and a Debian package. Use the AppImage when you want minimal system mutation; use the deb when you want a desktop-integrated install on Debian or Ubuntu style systems. ### AppImage Download, mark executable, and run from a user-owned location. ```bash chmod +x 'Ambient Desktop-0.1.97-linux-x86_64.AppImage' ./'Ambient Desktop-0.1.97-linux-x86_64.AppImage' ``` ### Debian package Install with apt so dependencies and desktop integration are handled by the package manager. ```bash sudo apt install ./Ambient\ Desktop-0.1.97-linux-amd64.deb ``` ### Container-backed capabilities ToolHive-backed MCP capabilities need Docker, Podman, or another supported container runtime. Verify the runtime before installing default web extraction capabilities. ### Keyring-sensitive integrations Google Workspace and other account-backed capabilities depend on the desktop keyring or an explicit fallback path. Headless Linux hosts need extra care. ## Build from source Source builds are for Ambient contributors and platform validation. Install **Git, Node.js, and pnpm** first, then clone the repository and build. Build each platform's artifacts on that platform so Electron native modules and signing behave correctly. Builds are unsigned unless signing credentials exist in your environment. Each block below is self-contained: copy it, paste it into your terminal, and you have the source cloned, dependencies installed, and either a dev session or a packaged build. ### macOS (Apple Silicon or Intel) Clone, install, then run in development or build a DMG. Signed release builds additionally need a Developer ID and notarization credentials. ```bash git clone https://github.com/ambient-xyz/AmbientDesktop.git cd AmbientDesktop pnpm install pnpm run dev # run in development pnpm run dist:mac # build the macOS app (DMG + ZIP) ``` ### Windows (x64, PowerShell) Install Git, Node.js, pnpm, Python, and the Visual Studio Build Tools first. Build on real Windows x64 so native modules match the platform. ```bash git clone https://github.com/ambient-xyz/AmbientDesktop.git cd AmbientDesktop pnpm install pnpm run dev # run in development pnpm run dist:win # build the Windows installer (NSIS + ZIP) ``` ### Linux (x64) Build Linux packages on Linux. Native modules such as node-pty and better-sqlite3 are rebuilt and verified under Electron during the build. ```bash git clone https://github.com/ambient-xyz/AmbientDesktop.git cd AmbientDesktop pnpm install pnpm run dev # run in development pnpm run dist:linux # build the AppImage + .deb ``` ### Verify the packaged build (all platforms) After packaging, confirm the native modules load inside the packaged Electron runtime before you publish or share artifacts. ```bash pnpm run test:packaged pnpm run verify:packaged-native ``` ## Post-install verification - Confirm the installed version and update channel. - Open Settings and verify provider configuration, local runtime status, browser capability status, and plugin/capability diagnostics. Settings search keeps provider, permission, and runtime configuration discoverable. - Install curated defaults only after descriptor, runtime, permission profile, and source provenance are visible. - Run a low-risk coding or documentation task first, then inspect the plan, artifacts, browser evidence, and Git summary before allowing broader automation. - Use Ambient-managed secret flows for provider keys and account integrations. Do not paste credentials into chat or documentation artifacts. ## Installation FAQ **Should I use the latest alias or a versioned URL?** Use latest aliases for ordinary installs. Use versioned URLs and SHA256SUMS when reproducing a release, writing support instructions, or validating a machine for release work. **Why can Windows show extra prompts?** Early Windows artifacts may not yet have mature Authenticode signing or installer reputation. SmartScreen and firewall prompts are expected until that hardening is complete. **Does installing the app make every capability available?** No. The desktop app can launch without every runtime. ToolHive-backed MCPs, local model hosting, browser automation, Google Workspace, and future Ambient Mini mining each have their own health checks and permission surfaces. **Can I build production artifacts on any platform?** No. macOS artifacts are built on macOS, Linux artifacts should be built on Linux, and Windows artifacts should be built on Windows because native modules and signing behavior are platform-specific. ## Keep going - [Quickstart](https://ambient.xyz/docs/use/desktop/quickstart): start in the Welcome Folder, finish setup, then run a small calculator task with visible proof - [Product north star](https://ambient.xyz/docs/use/desktop/north-star): the product thesis, Ambient Desktop as the workstation for agentic work on the Ambient network - [Security model](https://ambient.xyz/docs/use/desktop/security): what gets contained, and why the agent still works on your real desktop --- # Desktop quickstart > Start in the pinned Welcome Folder, finish Core and Plugin Setup, then run one small calculator task and inspect the proof it leaves behind. - Canonical: https://ambient.xyz/docs/use/desktop/quickstart --- Start in the Welcome Folder, finish setup, then run a small calculator task with visible proof. Install the app first (see [Install Ambient Desktop](https://ambient.xyz/docs/use/desktop/installation)) and keep the [Project Board](https://ambient.xyz/docs/use/desktop/project-board) page nearby for the third task path. A first session runs in that order: the product-owned Welcome Folder, then setup, then one small implementation task. The main Ambient Desktop shell combines chat, workspace context, navigation, and evidence panels in one local developer workstation. [Diagram: Welcome Folder Quickstart diagram. The Welcome Folder is a pinned project that starts at Instructions, then runs five ordered stages: Instructions (shell, icons, planner, board), Core Setup (guided setup and Settings), Plugin Setup (plugins and capabilities), Capability Readiness (ToolHive, Scrapling, providers), and First Useful Task (calculator in three modes). The quickstart flow is: follow UI, run task, inspect proof.] *Welcome Folder Quickstart: the first session follows the product-owned Welcome Folder, then setup, then a small implementation task.* ## Start in the Welcome Folder On first launch, Ambient creates a pinned project named Welcome Folder. Open it from the sidebar before starting a real task. The folder is the product-owned first-run curriculum, not a sample project. The Welcome Folder opens at the Instructions thread and includes two setup threads: Core Setup and Plugin Setup. It also copies product screenshots into the folder so the tour can show the actual shell, Planner Mode, Project Board, Draft Inbox, map view, Git summary, Plugin Manager, and Settings surfaces. ### 1. Open the pinned Welcome Folder Use the folder/project area in the sidebar and select Welcome Folder. If it is already open, stay there for the first session so the screenshots and seeded instructions match the workspace you are using. ### 2. Read the Instructions thread Use it as the live map of the shell: sidebar, composer, Planner Mode toggle, right-side work surfaces, Project Board, Git summary, browser, files, terminal, diffs, and Workflow Recordings. ### 3. Keep the Welcome screenshots nearby The screenshots in the Welcome Folder are the first visual references for this quickstart. They should match the product UI more closely than abstract diagrams. ## Finish Core Setup before relying on web research Open the Core Setup thread. The live setup card is generated from Ambient's provider catalog and Settings actions, so the buttons you see there are the same product entry points used elsewhere in the app. Click Start guided setup for the broad first-run path, or use Open Settings when you want to inspect a specific provider, permission, or runtime state. Setup chats are approval-gated: they should not silently install dependencies, bind secrets, download models, activate providers, or change provider selections. ### Search, web, and research Review search providers, scraping, retrieval, and deep research setup. For most developers, the important early check is whether public web extraction can work safely. ### MCP runtime and ToolHive Ambient uses ToolHive as the runtime boundary for MCP workloads. If Docker, Podman, or another supported container runtime is missing or not running, Core Setup should route you through recovery before installing default web capabilities. ### Default Scrapling capability Scrapling is Ambient's reviewed default public web extraction capability. It is installed through a pinned descriptor and ToolHive-managed workload, and individual tool calls still remain permissioned. ### Security and access Provider keys, browser credentials, permission grants, and account integrations stay in Ambient-managed approval surfaces. Do not paste secrets into chat. ## Optional: local research setup Local Research and Local Deep Research should be presented as an expandable path, not as a prerequisite for every first run. Enable it when you want local-first retrieval, managed local model assets, or lower-latency research loops on a machine that can support the runtime. **When should I expand local research setup?** Open it when your task benefits from local-first research, local model routing, or privacy-sensitive retrieval. Leave it collapsed for a normal first calculator task. **What does local research setup check?** It should walk through runtime readiness, managed model assets, llama.cpp availability, provider preference, memory telemetry, validation, and repair steps. **How does this relate to ToolHive and Scrapling?** ToolHive and Scrapling make public web extraction safer. Local Research is a separate optional path for local-first research and model-backed retrieval. ## Open Plugin Setup after Core Setup Plugin Setup is for extension surfaces that are not already covered by Core Setup: curated or imported Codex plugins, Pi packages, custom MCP servers, generated capabilities, and workspace-specific integrations. Use Open Plugins to inspect installed and importable capabilities. Use Create capability only when the existing catalog does not cover a narrow repeatable job. Generated capabilities should show their command contracts, dependency approvals, secret requests, validation, repair, update, re-registration, and removal actions. | Surface | What it covers | | --- | --- | | **Codex plugins** | Curated or imported bundles with skills, apps, and MCP servers | | **Generated capabilities** | Capability Builder packages that can be previewed, validated, repaired, updated, re-registered, and removed | | **Custom MCP** | Custom MCP servers that are not the default Scrapling web research path | | **Team integrations** | Plugins or generated capabilities for narrow internal tools with explicit inputs, outputs, secrets, and validation | ## Connect Google Workspace (optional) If you want Ambient to work with Gmail, Google Calendar, and Drive, connect a Google account from **Plugins → Install Capabilities → Google Workspace**. It is a one-time, five-step setup, and each step shows its own status so you always know what is left. You will need a Google account and a free Google Cloud project to create the OAuth client. This is a first-party connector, not a generic plugin: Ambient installs a pinned Google Workspace CLI, you supply your own Desktop OAuth client, and the connection is validated with read-only probes before anything depends on it. The five steps end in a read-only validation of Gmail, Calendar, and Drive. [Diagram: Google Workspace Setup diagram. A five-step flow inside Plugins, Install Capabilities, first-party connector: 1 Install the Workspace CLI (Install gws), 2 Create a Desktop OAuth client (Open Google Console), 3 Import the OAuth client JSON (Import OAuth JSON), 4 Connect your Google account (Connect account), 5 Validate connectors (Validate). Each step turns green as it completes; Validate runs read-only probes for Gmail, Calendar, and Drive.] *Google Workspace Setup: a five-step flow inside Plugins that ends in a read-only validation of Gmail, Calendar, and Drive.* ### 1. Install the Workspace CLI Click Install gws. Ambient downloads a pinned, checksum-verified Google Workspace CLI into its managed app data. There is no system-wide install to manage. ### 2. Create a Desktop OAuth client Click Open Google Console and create a Desktop application OAuth client in your own Google Cloud project: configure the consent screen, then download the client_secret JSON. The project, scopes, and consent stay yours. ### 3. Import the OAuth client JSON Click Import OAuth JSON and choose the downloaded client_secret file. Ambient copies it into local, tightly-permissioned storage. You never paste credentials into chat. ### 4. Connect your Google account Click Connect account to start a browser sign-in. You complete Google's login and consent yourself; Ambient never sees your password or 2FA code. The requested scopes cover Gmail, Calendar, and Drive. ### 5. Validate connectors Click Validate. Ambient runs quick read-only probes (list Gmail labels, list calendars, search Drive) and marks the account available once they pass. ## What you can do once Google is connected | Connector | What it does | | --- | --- | | **Gmail** | Search and read mail, list labels, and draft messages. Inside Workflows, Google access stays read-only by default | | **Calendar** | List calendars and search or read events. Event creation is gated and runs as a dry run by default inside Workflows | | **Drive** | Search files, read and export documents, and materialize files into your workspace through approved file handles | | **Multiple accounts** | Connect more than one account; when several are present, the agent asks which account a given request should use | **Why create my own OAuth client instead of signing in directly?** Connecting through your own Google Cloud project means the access, scopes, and consent belong to you, and a Desktop OAuth client keeps the credential local to your machine. **Google shows an "unverified app" warning. Is that normal?** Yes. While your OAuth client is in testing, Google shows an unverified-app notice and you must be listed as a test user on the consent screen. That is expected for a personal Desktop client. **Validation failed. What should I check?** Re-run Validate. The usual causes are a missing test-user entry, an API not enabled in your Cloud project, or a rotated client secret (download and re-import the new JSON). Each probe reports which connector failed. ## Run a calculator task three ways Use one contained task to learn the product: build a small calculator app with keyboard input, error states, and screenshot proof. Run it in a new folder so it is safe to inspect, delete, or repeat. The same task teaches three workflows (direct prompting, Planner-to-goal, and Planner-to-board): | Path | Where you start | What you get | | --- | --- | --- | | **1. Prompt it** | The composer, in a new folder | Changed files, screenshot proof, and Git status | | **2. Plan to goal** | Planner Mode | A durable plan you review and approve before implementation | | **3. Plan to Project Board** | Planner Mode, then a board | Draft Inbox cards you accept individually, with per-card proof | [Diagram: Calculator Task Paths diagram. One contained Build a calculator task (keyboard input, errors, screenshot proof) teaches three workflows: Prompt it (single request, inspect result, Git summary), Plan to goal (Planner Mode, answer decisions, implement plan), and Plan to board (Draft Inbox, run cards, review proof). All paths end with changed files, screenshot proof, Git status, and next-step guidance.] *Calculator Task Paths: one contained calculator task teaches direct prompting, Planner-to-goal, and Planner-to-board.* ### Path 1: prompt it Create a new folder and ask: ```text Build a small calculator app with keyboard input, clear error states, and screenshot proof. Keep the implementation simple and show me the changed files and Git status when done. ``` ### Path 2: plan to goal Switch to Planner Mode first. Ask for the same calculator, answer the required decisions, review the durable plan, then approve implementation from the plan. ### Path 3: plan to Project Board Start in Planner Mode, create a board from the plan, review Draft Inbox cards, accept only the useful cards, run one card, then inspect proof before running the rest. ## What to inspect before you trust the result - Changed files: inspect the files or diff panel rather than trusting the final message alone. - Screenshot proof: confirm the calculator actually rendered and the UI state is visible. - Terminal or validation output: check whether commands ran, failed, or were skipped. - Project Board evidence: if you used the board path, inspect Draft Inbox choices, card proof, and map relationships. - Git summary: confirm branch, worktree status, changed files, and whether a commit is appropriate. ## Quickstart FAQ **Do I need ToolHive before every task?** No. A local calculator task can run without ToolHive. You need ToolHive readiness when using ToolHive-backed MCP workloads such as the default Scrapling public web extraction capability. **What if Core Setup says the container runtime is missing?** Install or start Docker Desktop, Podman, or another supported runtime, then rerun the ToolHive readiness check before installing Scrapling. **Should I start with Project Board?** Use direct prompting for a tiny task. Use Planner Mode when you want decisions recorded. Use Project Board when you want Draft Inbox review, card-level execution, dependencies, and durable proof. ## Keep going - [Project Board](https://ambient.xyz/docs/use/desktop/project-board): turns goals into durable plans, task cards, source-backed evidence, and review loops - [Durable goals](https://ambient.xyz/docs/use/desktop/durable-goals): plan, evidence, and continuation state persisted to disk, so work keeps its shape across turns, pauses, and restarts - [Provider routing](https://ambient.xyz/docs/use/desktop/provider-routing): prioritize and fall back through providers for search, fetch, browser, media, and model-adjacent work --- # Project Board > Turn large or ambiguous goals into a Kanban of source-backed cards with evidence, dependencies, and a review loop instead of a transcript you scroll. - Canonical: https://ambient.xyz/docs/use/desktop/project-board --- Project Board is Ambient Desktop's planning and execution surface for long-running agent work: it turns goals into durable plans, task cards, source-backed evidence, and review loops. > [!NOTE] Developer Preview > The core Project Board workflow is usable today; some advanced card states > and validation paths are still being hardened. [Diagram: Project Board Lifecycle diagram. Four numbered stages run left to right. Stage 1 Capture holds Goal, Sources, Clarifications, and Draft inbox, and captures context. Stage 2 Plan holds Cards, Dependencies, Budgets, and Owners, and shapes plan. Stage 3 Execute holds Threads, Artifacts, Evidence, and Retries, and executes work. Stage 4 Review holds PM review, Proof judgment, Git summary, and Next slice, and reviews proof. A board proof state chip lists cards, evidence, and review.] *Project Board Lifecycle: four stages (Capture, Plan, Execute, Review) with proof carried across all of them.* In short: a goal moves through Capture, Plan, Execute, and Review, carrying a proof state of cards, evidence, and review from start to finish. ## When to use it Use Project Board when a request is too large, ambiguous, or important to live only in chat: work that needs decomposition, source grounding, pause/resume, review, and proof. Typical starting points: implement a feature across several files, investigate a regression, compare architecture options, validate release readiness, or turn a vague product request into ordered implementation cards. Use plain chat for small single-step tasks. Reach for the board when the work has multiple dependent steps, needs your review before execution, or must preserve proof across pauses and restarts. ## End-to-end flow A board moves through four stages: 1. **Capture.** Ambient records the goal, relevant files or artifacts, known constraints, and open questions, which gives the planner a bounded context instead of a giant prompt dump; proposed cards land in the Draft Inbox. 2. **Plan.** Accepted cards get dependencies, budgets, and owners; the plan takes shape as a reviewable structure rather than free text. 3. **Execute.** Cards run as threads that produce artifacts, evidence, and retries. 4. **Review.** The PM review judges proof, the Git summary is inspected, and the next slice of work is chosen. Ambient can propose cards automatically from a goal and its source context; the Draft Inbox exists precisely so you review and shape that plan before it becomes committed work. ## The surfaces - The **Draft Inbox** is a staging area for candidate cards, implementation choices, and clarifying questions before they become committed work. You can accept, refine, defer, or reject each one, which keeps the board from filling with unreviewed or low-confidence work. - The **Kanban Board** is the main execution surface. Cards expose status, scope, source evidence, validation, owner/runtime context, and next actions. - **Map View** is a relationship view for dependencies, artifacts, cards, and decisions. It helps you see whether work is converging or branching. - **Proof and Review** is a compact record of what changed, what was validated, what remains risky, and which evidence supports the final answer. Proof surfaces attach commands, screenshots, source paths, and final notes to the work product. ## Card state and evidence Project Board is effective because cards are not just labels. They are durable units of work that preserve why the work exists, where evidence came from, what was attempted, which artifacts were produced, and how completion was judged. Every card carries one of a fixed set of statuses: proposed, accepted, active, blocked, review, and complete. Work can pause and resume without losing the shape of the plan. A card carries: | Field | What it holds | | --- | --- | | Source references | Files, docs, screenshots, traces, and external facts the card is grounded in | | Status | Current state, dependencies, and budget | | Validation | Commands or product checks that prove the card | | Artifacts | Documents, screenshots, logs, and diffs the work produced | | Review notes | Review judgment, proof quality, and follow-up risks | When a board finishes, the Git summary and review surfaces connect the result to branch state, diffs, and acceptance criteria. That is the handoff from agent work to your normal source-control review. ## How it relates to durable goals [Durable goals](https://ambient.xyz/docs/use/desktop/durable-goals) are the persistence engine: they preserve the overall objective and continuation state on disk. Project Board is the most visible surface on top of that engine, giving a goal a card structure with evidence and review points. You do not choose between them; a board is how you watch and steer a durable goal. ## Keep going - [Durable goals](https://ambient.xyz/docs/use/desktop/durable-goals): the engine underneath the board - [Symphony](https://ambient.xyz/docs/use/desktop/symphony): delegating card work to child agents - [Workflow Recorder](https://ambient.xyz/docs/use/desktop/workflow-recorder): turning a successful run into a reusable workflow --- # Durable goals > Long-running goals persist their plan, evidence, and continuation state to disk, so work survives restarts and context limits instead of dissolving into a chat transcript. - Canonical: https://ambient.xyz/docs/use/desktop/durable-goals --- Durable goals are the persistence engine underneath Ambient Desktop's long-running work: the plan, its evidence, and the continuation state are written to disk and worked in a loop that can stop and resume. [Diagram: Durable Goal Loops diagram. Four numbered stages run left to right. Stage 1 Goal holds Objective, Budget, Plan, and Status, and sets objective. Stage 2 Loop holds Work slice, Validate, Update plan, and Persist, and executes slice. Stage 3 Resume holds Read state, Continue, Repair, and Avoid drift, and persists state. Stage 4 Complete holds Audit, Proof, Commit, and Report, and reports proof. A durable goal state chip lists plan, budget, and proof.] *Durable Goal Loops: long-running goals persist plans, evidence, and continuation state across turns and restarts.* In short: a durable goal cycles through Goal, Loop, Resume, and Complete, persisting its plan, budget, and proof to disk at every step. ## Why durable goals exist A normal chat agent holds its plan in the conversation. Close the window, hit a crash, or run long enough that context is trimmed, and the plan is gone; the agent silently restarts from whatever it can still remember. For multi-step work, that is how tasks drift, repeat themselves, or quietly stop halfway. Ambient instead writes the objective, the current plan, validation evidence, and continuation state to disk, then works the goal in a loop it can stop and resume. Give it a goal that takes hours, not seconds, and the work keeps its shape across turns, pauses, and restarts. Progress becomes a thing you can look at, not a thing you hope the model still has in context. ## The six-step loop Every durable goal runs the same loop, and each step leaves a record, so you can always see where the goal is and what it has proven. The diagram above groups it into four visible phases (Goal, Loop, Resume, Complete); here it is broken into the six steps the engine actually runs: 1. **Plan.** The goal becomes an ordered plan with a budget and explicit decisions. In Planner Mode you answer the open questions before work begins. 2. **Act.** The agent executes the next slice of the plan (edits, commands, research, or a child agent) instead of trying to do everything in one turn. 3. **Validate.** The slice is checked against its expected result with tests, commands, screenshots, or a review pass, and the evidence attaches to the work product. 4. **Persist.** The updated plan, evidence, and continuation state are written to disk, so nothing important lives only in the conversation. 5. **Resume.** After any interruption, the agent reads the persisted state and continues, repairing anything stale rather than starting over. 6. **Audit.** Completion is judged against the original objective. A goal is not done because the agent said so; it is done when the audit passes. ## What gets persisted Four things are kept on disk and kept current: - **The objective**: the goal itself and its decisions, so success can be measured against what you actually asked for. - **The live plan**: the current ordered steps, their status, and the budget, kept current rather than allowed to drift. - **Evidence**: validation output, artifacts, screenshots, and source references, attached to each step. - **Continuation state**: where the loop is and what comes next, so a resume picks up from saved state instead of memory. If the app restarts mid-goal, Ambient reads the persisted plan, evidence, and continuation state and resumes from there. A reconciliation step repairs stale cache and missing artifacts before continuing, so a restart costs some progress, not the whole task. ## Where you stay in control Durable does not mean unattended. Planner Mode and the Project Board's Draft Inbox are the review points: you approve decisions and cards before the loop expands execution. ## Goals, the board, and Symphony Durable goals are the engine; the [Project Board](https://ambient.xyz/docs/use/desktop/project-board) is the most visible way to see one, with the goal's plan rendered as cards with evidence and review surfaces. For goals that need more than one role or context window, a goal can drive [Symphony](https://ambient.xyz/docs/use/desktop/symphony) to delegate scoped work to child agents and join their artifacts back into the plan. ## Keep going - [Project Board](https://ambient.xyz/docs/use/desktop/project-board): the visible surface on top of the engine - [Symphony](https://ambient.xyz/docs/use/desktop/symphony): multi-agent delegation for large goals - [Workflow Recorder](https://ambient.xyz/docs/use/desktop/workflow-recorder): turning a proven path into a reusable workflow --- # Symphony > Multi-agent orchestration: a parent session owns the objective, budget, and approvals, and delegates scoped work to typed child agents joined back through artifacts. - Canonical: https://ambient.xyz/docs/use/desktop/symphony --- Symphony is Ambient Desktop's orchestration system for work that benefits from more than one role, context window, runtime, or review posture. The model: one parent session owns the work, typed child agents receive scoped slices of it, and an artifact-driven join brings everything back. [Diagram: Symphony Orchestration Topology diagram. A parent session (owning the objective, budget, and approvals) delegates scoped work down to four child agents: a research child (search, citations, source notes); an implementation child (file edits, commands, artifacts); a review child (tests, proof, risks); and a local-model child (private data, cheap loops, vision). An artifact-driven join brings back summaries, conflicts, metrics, board cards, and final proof. Callable workflows can package approved orchestration recipes.] *Symphony Orchestration Topology: parent sessions coordinate scoped child agents through role policy, artifacts, and explicit joins.* > [!WARNING] In Development > Symphony is in development. The contracts, recipes, tests, scoped child > launches, and UI concepts exist, but advanced orchestration is presented > as guided patterns with explicit limits rather than as fully open-ended > autonomous delegation. ## What Symphony is for Symphony is not a generic swarm button. A **parent session** owns the objective, budget, approval posture, and final synthesis, while children receive scoped work and return artifacts. Use it when a single agent would either carry too much context, mix incompatible responsibilities, or review its own work without enough independence. ## Child agent types Each child has a defined role and a defined boundary on what it must not decide: 1. A **research child** collects source evidence: links, screenshots, logs, and structured notes. It returns citations and uncertainty, not final product decisions. 2. An **implementation child** works on a bounded slice with an explicit file or command scope, returning artifacts, changed files, and validation output. 3. A **review child** checks the parent or an implementation child against acceptance criteria, tests, security constraints, and user intent, identifying gaps and assessing proof quality. 4. A **local-model child** uses local runtimes for privacy-sensitive, low-cost, visual, or repetitive work where a local model is the right fit. 5. A **workflow child** executes a confirmed [workflow artifact](https://ambient.xyz/docs/use/desktop/workflow-recorder) with known parameters, prerequisites, and expected outputs. ## Orchestration patterns 1. **Fan-out research.** The parent splits a broad question into research children with different source scopes; children return evidence bundles, and the parent joins them into a ranked synthesis with conflicts called out. 2. **Plan decomposition to Project Board.** The parent turns an objective into card candidates, then uses children for selected implementation or validation work. The [Draft Inbox](https://ambient.xyz/docs/use/desktop/project-board) remains your review point before execution expands. 3. **Implementation plus independent review.** One child implements a bounded change while another reviews tests, edge cases, and proof; the join step compares their artifacts before the parent presents a final answer. 4. **Local/cloud model split.** The parent routes private, cheap, or specialized subtasks to local models while reserving harder synthesis or network-native tasks for Ambient or another selected provider. 5. **Callable workflow orchestration.** A reviewed workflow runs as a child-like executable unit: the parent supplies parameters and joins the workflow's artifact back into the larger task. ## The control surface - **Role policy**: what each child is responsible for and what it must not decide. - **Tool grants**: which tools, files, providers, browser surfaces, or local runtimes each child may use. - **Context boundary**: what the child receives up front and what it can discover later. - **Budget and stop conditions**: token, time, retry, and approval limits for each child. - **Mailbox and artifact join**: how summaries, conflicts, metrics, board cards, and final proof return to the parent. ## A worked example A parent receives: *"Add keyboard shortcuts to the calculator and prove they work."* It creates three children (a research child to inspect the existing UI and shortcut conventions, an implementation child to edit the calculator, and a review child to run or inspect validation), then joins their artifacts into a final answer with changed files, proof, and remaining risks. ## Keep going - [Durable goals](https://ambient.xyz/docs/use/desktop/durable-goals): the persistence engine a Symphony run hangs off - [Project Board](https://ambient.xyz/docs/use/desktop/project-board): where decomposed work becomes reviewable cards - [Workflow Recorder](https://ambient.xyz/docs/use/desktop/workflow-recorder): packaging an approved recipe as a callable unit --- # Workflow Recorder > Record a successful multi-step task once, review and generalize it with Ambient, and re-run it as a parameterized, callable workflow. - Canonical: https://ambient.xyz/docs/use/desktop/workflow-recorder --- Workflow Recorder captures a real, successful task and turns it into a reusable artifact: Ambient reviews the recording, extracts the parameters, and registers a callable workflow you can invoke again like a reviewed tool. > [!WARNING] In Development > Workflow Recorder is in development. Important building blocks exist, but > UX, contracts, and validation are still moving. See [maturity > labels](https://ambient.xyz/docs/resources/maturity-labels). [Diagram: Recorder To Callable Workflow diagram. A five-stage pipeline runs left to right: Record a real task, then Research (search and scrape), then Judge (LLM scores), then Generalize (parameters), then Call (reusable tool). A note beneath the pipeline says the recording documents screenshots, review states, edit points, confirmation, and invocation examples, and that a confirmed workflow should feel like a reviewed capability, not a buried chat memory.] *Recorder To Callable Workflow: a successful recording becomes a reviewed, parameterized, reusable workflow artifact.* ## When to record a workflow **Workflow discovery** turns repeated work into inspectable candidates before they become callable artifacts. Use the recorder when a task is likely to repeat and the successful path matters: research routines, release checks, connector setup, report generation, QA passes, or internal procedures with known review steps. Do not record one-off work just to save a transcript; a transcript already does that. A good recording becomes a reviewed playbook with parameters, policy notes, validation expectations, and a callable shape. That is what makes a confirmed workflow different from a saved prompt: it records the successful *process* (parameters, permissions, validation, and the output contract), not just the words that kicked it off. ## Example: NYC date night research This example teaches the full lifecycle: record a real research task, use search and scraping, ask an LLM to judge the options, rerank based on critical reviews, generalize the workflow, confirm it, then call it later as a reusable artifact. It is deliberately a non-code task. ### 1. Start a recording and give the first prompt Open **Workflow Recordings** and click **New Workflow Recording**. Name it *NYC date night research and review ranking*, and keep the task narrow enough that a future user could rerun it with a different city, date, budget, and vibe. Then give the task prompt: > Find date night activities in New York City for this Friday. Include > price, neighborhood, reservation constraints, weather sensitivity, > links, and why each option could be memorable. While the recording runs, the UI makes it clear that a workflow is being recorded, and that tool calls, user decisions, validation results, and output shape are being captured for review. ### 2. Let Ambient research, then add judging and reranking Allow search and public web extraction, and Ambient researches with visible providers (you can see which search and extraction paths ran). If Scrapling or web research is not ready, finish Core Setup in the [quickstart](https://ambient.xyz/docs/use/desktop/quickstart) before continuing rather than assuming the workflow can proceed. Then add a judging step that scores each candidate on novelty, logistics, cost, conversation quality, weather risk, and reservation friction, and requires short rationales rather than bare numbers. Finish with a critical-review step that reranks candidates when public reviews contradict a venue's own description, keeping citations and explaining any ranking changes. ### 3. Produce the final artifact The run ends with a concrete output: a ranked shortlist with reservation links, a backup option, travel and logistics notes, and a short avoid list. ### 4. Review with Ambient, edit, and confirm End the recording and click **Review with Ambient**. The review summarizes the successful path, identifies parameters, lists preconditions, flags any secrets or private data, and drafts the reusable workflow. For this example, the generalized parameters are city, date, budget, party size, neighborhood preference, vibe, mobility constraints, and review-weighting. The review produces a draft playbook you can edit, not an opaque memory: you edit parameters, remove sensitive data, and confirm the contract. Confirm only after validation, failure modes, and expected outputs are clear. ### 5. Call the confirmed workflow Start a new chat and invoke the workflow with a different city or date. The confirmed artifact is discoverable and invokable like a reviewed tool, with inputs, expected outputs, and policy notes, and it is exposed through the callable workflow registry. You get a callable artifact card and the proof that the run reused the reviewed playbook. ## Generalization rules Five rules govern how a recording becomes a safe, reusable artifact: 1. **Parameterize task-specific inputs**, so hidden local paths, dates, locations, accounts, and personal preferences never get replayed from the artifact. 2. **Redact secrets and workspace-private data** before confirmation. 3. **Record preconditions**: required providers, web access, connectors, local runtimes, and model capabilities. 4. **Preserve the contract**: expected outputs, validation commands, failure modes, retry policy, and stop conditions. 5. **Register only after review**: the artifact reaches the callable workflow registry only once confirmed. High-impact steps (web extraction, connector access, filesystem changes, and workflow invocation itself) stay approval-gated and visible when a workflow runs. ## What not to record Never preserve raw secrets, private credentials, one-off personal data, or hidden local paths in a recording. Use Ambient-managed secret flows and parameterize sensitive inputs instead. Workflows that depend on providers (Scrapling or others) record those prerequisites and their fallback expectations, and run only where the provider is installed, permitted, and appropriate; see [Provider routing](https://ambient.xyz/docs/use/desktop/provider-routing). ## Keep going - [Symphony](https://ambient.xyz/docs/use/desktop/symphony): running a confirmed workflow as a child unit in a larger orchestration - [Project Board](https://ambient.xyz/docs/use/desktop/project-board): where repeated work meets planning and review - [Provider routing](https://ambient.xyz/docs/use/desktop/provider-routing): the providers a workflow's research steps route through --- # Provider routing > Ambient orders search, fetch, browser, vision, and local-model providers by your preference and task fit, with policy checks and visible fallback evidence when one is skipped. - Canonical: https://ambient.xyz/docs/use/desktop/provider-routing --- Provider routing is how Ambient Desktop decides which capability handles a given step: which search provider, which fetch or scraping path, when to open a real browser, and when local models or vision runtimes are the right fit. Ambient can prioritize and fall back through providers for search, fetch, browser, media, and model-adjacent work. Agent success often depends on selecting the right capability for the job. Search, scraping, browser content, vision, local runtimes, and model providers have different strengths, privacy boundaries, costs, and failure modes. [Diagram: Provider Preference And Fallback diagram. A four-node decision chain runs left to right. User preference (Settings order, or a chat override) leads to Task fit (search, fetch, browser; or vision or a local runtime), then to Policy check (privacy and URL scope; secrets and cost), then to Provider attempt (success or timeout; blocked or a weak result). A fallback evidence chip records the skip reason, retry path, and final source attribution.] *Provider Preference And Fallback: Settings and chat preferences guide provider choice while policy, task fit, and evidence determine fallback.* ## How a routing decision flows Provider choice is a user preference plus a runtime decision. Each attempt passes through four checks: 1. **User preference**: your Settings ordering, or a chat override for this task. 2. **Task fit**: search, fetch, browser, vision, or a local runtime, depending on what the step needs. 3. **Policy check**: privacy posture, URL scope, secrets, and cost. 4. **Provider attempt**: success, timeout, blocked, or a weak result that triggers the next provider in line. When a fallback happens, Ambient preserves the evidence: the attempted provider, the reason for the fallback, the next provider tried, the final source attribution, and any confidence limits. ## Where preferences live - **Settings** (durable) holds provider priority, local-first posture, privacy boundaries, disabled providers, API key setup, runtime repair, and default fallback behavior. The provider ordering persists until you change it. Settings search keeps provider, permission, and runtime configuration discoverable. - **Chat** (task-local) steers one run without touching Settings: "prefer local research for this task", "try Exa first", "use browser content only if search is insufficient", "avoid cloud vision for this screenshot". A chat preference overrides ordering for that run only, and it cannot bypass policy or missing setup. - **Welcome Core Setup** is where you go when the provider is not ready. It routes you to ToolHive, Scrapling, Local Research, voice, vision, document, or access setup before a task depends on that provider. For web-heavy tasks, configure search, ToolHive, and Scrapling first. For local-first tasks, configure Local Research and the local model runtimes. For screenshot work, configure visual analysis or browser paths. ## Provider roles - **Search** returns links and snippets; it does not replace full source inspection. - **Scraping and fetch** extract page content. Scrapling, the reviewed default for public web extraction, runs through ToolHive when you need isolated extraction. - The **browser** is for when rendering, login state, screenshots, or page interaction matters; browser runs preserve evidence and respect URL policy. - **Local models and vision** cover privacy-sensitive, latency-sensitive, low-cost, image-analysis, and local-first work when the selected runtime is ready. ## Reading a skip When a provider is skipped, the recorded reason comes from a small taxonomy: disabled, missing credentials, blocked by policy, unavailable, timed out, or not suited to the task. That skip reason plus the retry path and final source attribution is the troubleshooting trail. It tells you whether to fix credentials, enable a provider, adjust policy, or confirm that the router picked a better-fitting path. ## Example prompts Three task-local steering prompts you can paste into chat: ### Prefer local-first research ```text For this task, prefer local research and local models where possible. Use public web providers only if local sources are insufficient, and tell me when fallback happens. ``` ### Use search then browser ```text Search first. If the result pages need rendering or screenshots, fall back to browser content. Keep citations and explain any blocked pages. ``` ### Use Scrapling for public pages ```text Use the reviewed Scrapling capability for public web extraction if it is installed. If ToolHive or Scrapling is not ready, tell me exactly which setup step is missing. ``` ## Keep going - [Ambient Desktop overview](https://ambient.xyz/docs/use/desktop): Core Setup and the first-run flow where providers get configured - [Workflow Recorder](https://ambient.xyz/docs/use/desktop/workflow-recorder): workflows record their provider prerequisites and fallback expectations - [Symphony](https://ambient.xyz/docs/use/desktop/symphony): the local/cloud model split as an orchestration pattern --- # Remote control > Drive a running Ambient Desktop from Telegram, owner-authenticated and preview-then-approve, with anti-replay protection. Check status, change settings, and run work away from the window. - Canonical: https://ambient.xyz/docs/use/desktop/remote-control --- Ambient Desktop is a workstation you normally sit in front of. Remote control lets you reach a running instance from a messaging app instead: check status, change supported settings, run work, and handle approvals without sitting at the window, so work keeps moving while you are away from the machine. Telegram is the first supported provider; the gateway is built to add more. Remote control does not turn Ambient into a server daemon. The desktop app must be running with its window open; what it removes is the need to be *at* the window. Every remote action is owner-authenticated, and anything that changes state is approval-gated, the same review posture Ambient applies to in-app work. > [!NOTE] Developer Preview > Remote control ships as a Developer Preview. Telegram is wired end to end; > other providers, and some settings, are not yet reachable remotely. See > [Boundaries and current limits](#boundaries-and-current-limits). ## How a remote command flows A message does not run directly. It travels through the same preview-then-approve path the agent uses for any consequential action, with an owner check at the front. ### 1. Owner authentication Each remote binding is tied to a specific owner account on the provider. Messages from anyone else are not treated as commands, so a stray chat cannot drive your machine. ### 2. Preview The incoming command is parsed and previewed first: Ambient shows what it would do and flags any blockers before anything is applied. ### 3. Approval Commands that change state are approval-gated. You confirm from chat (for example, `approve request 1`) and only then does the action apply. Read-only status and navigation do not need approval. ### 4. Apply and relay The approved command runs against the live runtime, and the result (status, queued events, or the outcome) is relayed back to you in the same conversation. Remote commands cannot skip approvals. They flow through the same preview-then-approve path as in-app actions. ## Providers The gateway is a provider-agnostic surface, so new messaging apps can be added behind the same owner-auth and approval model. Only Telegram is wired end to end right now; every other provider carries a label that is ahead of its implementation rather than a claim that it works. | Provider | Status | Detail | | --- | --- | --- | | **Telegram** | Supported | The one fully wired provider. A local bridge connects to Telegram with your own API credentials, an owner handoff binds your account, and Ambient polls for your commands. Status reads, settings changes, project/chat/workflow actions, and approvals all work through it. | | **Signal** | Planned | Scaffolding and a contract exist, but the provider is intentionally disabled: it reports as unavailable and bindings are refused, until a reviewed local-bridge adapter lands. Ambient can plan the work, but cannot operate Signal yet. | | **WhatsApp, Matrix, and others** | Roadmap | The goal is many providers through the same gateway. Each one needs a reviewed adapter for owner auth, inbound delivery, and replies before it is offered. | ## What you can do remotely Ambient keeps an internal ledger of which actions are ready for remote use, which are partial, and which are still planned, so the agent never promises a remote capability it cannot actually perform. Today the ready set covers the common operating loop: - **Read status and navigate**: runtime status, projects, chats, workflow agents, and pending approvals, all without the window. - **Change supported settings**: voice, speech input, generated-media playback, search routing, chat mode, thinking level, and planner finalization. - **Run work**: create and switch projects, create chats, and create, run, compile, approve, retry, resume, or cancel workflow agents. - **Handle approvals**: review and approve or deny pending permission prompts, and revoke active grants, from chat. ## Setup at a glance Telegram setup is owner-driven and deliberately explicit. Ambient provides an activation plan and walks the steps rather than flipping a single switch. ### 1. Bring your own Telegram credentials The local bridge connects to Telegram using your own Telegram API credentials. They stay on your machine; Ambient runs the bridge as a local process. ### 2. Bind your owner account An owner handoff links the conversation to your account, so Ambient knows which sender to trust as the owner. ### 3. Start polling with a freshness mark Ambient polls the owner chat for commands. Activation passes a freshness timestamp, so old unread messages from before setup are treated as stale instead of being replayed as commands. That is the anti-replay guard. ## Boundaries and current limits The Developer Preview scope, stated plainly: - The desktop app must be running with its window open. This is remote control of a live instance, not a headless server you can SSH into. - Telegram is the only working provider; Signal is planned and other providers are on the roadmap. - Only a subset of settings are remotely writable today; provider selection, appearance, API keys, and some others are read-only or not yet exposed. - Polling freshness depends on activation passing the timestamp correctly. The activation plan handles it, but account for it when debugging why a message was ignored. - Every state-changing command is approval-gated by design, so remote operation is interactive, not fully unattended. ## FAQ **Can Ambient run on a headless server with no display?** Not in this preview. Remote control assumes the desktop app is running on your machine with its window open. It removes the need to interact with the window, not the need for the app to be running. **Can someone else message the bridge and control my machine?** No. Commands are owner-authenticated against a specific provider account, and state-changing actions require your approval from chat. Messages from non-owners are not treated as commands. **Is Signal supported?** Not yet. The provider is scaffolded but intentionally disabled and reports as unavailable. Ambient can plan reviewed Signal support, but cannot operate it today. **Do remote commands skip the usual approvals?** No. Remote commands flow through the same preview-then-approve path as in-app actions. Read-only status is free; anything that changes state is gated. ## Keep going - [Durable goals](https://ambient.xyz/docs/use/desktop/durable-goals): the long-running work you check in on remotely - [Symphony](https://ambient.xyz/docs/use/desktop/symphony): parent and child agents with scoped tools, role policy, artifacts, and join logic - [Project Board](https://ambient.xyz/docs/use/desktop/project-board): pending approvals and card state you can read from chat - [Security model](https://ambient.xyz/docs/use/desktop/security): the containment posture the approval gate belongs to - [Ambient Desktop overview](https://ambient.xyz/docs/use/desktop): what the app is and the surfaces it ships - [Install Ambient Desktop](https://ambient.xyz/docs/use/desktop/installation) and the [quickstart](https://ambient.xyz/docs/use/desktop/quickstart): install and first-run setup --- # Security model > Ambient Desktop sandboxes the capability, not the agent, with ToolHive containers, descriptor review, permission profiles, secret redaction, and audit artifacts, while the agent keeps working on your real desktop. - Canonical: https://ambient.xyz/docs/use/desktop/security --- Most agent tools protect you by sandboxing the whole agent, which also blinds it. Ambient does the opposite: the agent works on your real desktop, while the genuinely risky capabilities are the things that get contained. [Diagram: Capability Security Boundary. Risky capabilities (an MCP server, a browser page scraper, and a Pi package) are routed through Ambient mediation, which applies a ToolHive contained MCP runtime, descriptor review, a permission profile, secret redaction, and audit artifacts. In parallel, the regular desktop (its files and tools) remains directly usable. The result: high-risk capability is bounded, approvals are visible, and proof is reviewable.] *Capability Security Boundary: Ambient contains risky capabilities while preserving useful agent access to the regular desktop.* In short: risky capabilities pass through Ambient mediation (ToolHive containment, descriptor review, permission profiles, secret redaction, and audit artifacts) while the regular desktop stays directly usable: risk is bounded, approvals are visible, and proof is reviewable. ## Sandbox the capability, not the agent If you lock an agent inside a VM, it stays safe and useless: it can no longer touch the files, terminals, and tools that make a desktop agent worth running. Ambient draws the boundary in a more useful place. The agent operates on your regular machine, with real filesystem and terminal access, and the specific high-risk surfaces (third-party MCP servers, autonomous browsing and scraping, privileged package installs) are the ones that run inside containers, behind policy, with redacted secrets. ## What gets contained Not every action is risky, so not everything is treated the same. Ambient classifies capabilities by blast radius and contains the ones that warrant it: the three surfaces in the diagram above, plus privileged installs. | Capability | How it is contained | | --- | --- | | **MCP servers** (third-party code) | Run inside ToolHive-managed containers with an explicit allow list, instead of as trusted processes on your host | | **Browser & scrapers** (hostile pages) | Run with URL policy and private-address protection, because any page can be adversarial. See [Browser and scraping safety](https://ambient.xyz/docs/use/desktop/browser-scraping) | | **Pi packages** (tool-shaped extensions) | Sandboxed Pi support keeps tool-shaped packages separate from privileged extensions, with sanitized artifact paths | | **Privileged installs** (host mutation) | Packages that want lifecycle hooks, native dependencies, or host changes get explicit privileged review before they run | > [!WARNING] Container runtime required > ToolHive-backed capabilities depend on a container runtime (Docker, > Podman, or equivalent) being installed and healthy. Setup checks for one > and routes you through recovery if it is missing. Two of these surfaces have their own pages: [curated defaults](https://ambient.xyz/docs/use/desktop/curated-defaults) covers which capabilities ship reviewed, pinned, and sandboxed instead of installable on an agent's own initiative, and [browser and scraping safety](https://ambient.xyz/docs/use/desktop/browser-scraping) covers URL policy, private-address protection, bounded outputs, and the escalation ladder for web work. ## How an approval flows Containment is only half the story; the other half is that you can see and gate what happens. A high-impact action moves through a visible policy path before it executes. ### 1. Descriptor review Before a capability runs, Ambient Desktop reads its descriptor (command, arguments, environment, and requested permissions) so the request is legible, not opaque. ### 2. Permission profile Each capability runs under a permission profile (allow, deny, prompt, or audit) scoped to a thread, workspace, or process. Defaults are conservative. ### 3. Visible approval Sensitive actions (web extraction, connector access, filesystem changes, workflow invocation) surface a permission prompt with the grantable scope, instead of happening silently. ### 4. Audit artifact Every tool call and permission decision is recorded with a timestamp, alongside inspectable evidence (output, screenshots, and logs) rather than an unverifiable summary, so there is a trail you can review after the fact. ## Secrets stay out of the transcript Provider keys, browser credentials, and account tokens move through Ambient-managed secret flows. They are never pasted into chat and never written into transcripts or cached artifacts. Diagnostics are redacted, and artifact paths handed to sandboxed tools are sanitized so they cannot leak absolute paths, parent-directory traversal, or raw URLs. Do not paste secrets into chat; use the managed secret flows instead. ## What this does and does not cover Ambient labels its security posture honestly. The container boundary for MCP, the permission prompts, secret redaction, and audit artifacts are real and exercised by release gates. This model contains third-party MCP servers, web content, and package installs, including privileged ones, which get explicit review. [Privileged installs](https://ambient.xyz/docs/use/desktop/plugins), [hosted model endpoints](https://ambient.xyz/docs/use/desktop/provider-routing), and [local runtime exposure](https://ambient.xyz/docs/use/desktop/local-models) are higher-risk paths that carry their own maturity labels and validation references. They are not presented as finished. ## FAQ **Does the agent run with full access to my machine?** The core agent works on your regular desktop, but high-risk capabilities are contained: MCP servers run in ToolHive containers, browser and scraper access is policy-bounded, and privileged installs require review. Sensitive actions prompt for approval. **Where do my API keys go?** Into Ambient-managed secret flows, scoped to the capabilities that need them. They are redacted from diagnostics and never written into chat or transcripts. Do not paste secrets into chat. **Can I see what a capability did?** Yes. Permission decisions and tool calls are recorded as audit artifacts, and results come back as inspectable evidence (output, screenshots, and logs) rather than an unverifiable summary. ## Keep going - [Privacy and data retention](https://ambient.xyz/docs/use/desktop/privacy): what leaves your machine, and what the provider keeps - [Curated defaults](https://ambient.xyz/docs/use/desktop/curated-defaults): the reviewed, pinned, sandboxed capabilities that ship as the default catalog - [Browser and scraping safety](https://ambient.xyz/docs/use/desktop/browser-scraping): how untrusted pages are bounded by policy, isolation, and visible approval - [Plugins and marketplace](https://ambient.xyz/docs/use/desktop/plugins): the install classes and the Capability Builder --- # Curated defaults > Ambient Desktop ships a small set of reputable, reviewed, pinned, and sandboxed capabilities as its default catalog, so the common tasks work without an agent installing unvetted packages. - Canonical: https://ambient.xyz/docs/use/desktop/curated-defaults --- The fastest way to compromise an agent is to let it install anything. Ambient Desktop ships a small set of reputable, reviewed, sandboxed capabilities as defaults, so common tasks work out of the box without gambling on unknown packages. A default capability is selected, described, pinned, sandboxed, and validated before it becomes an easy install path. [Diagram: Curated Default Capability Chain, the trusted capability path: curate, sandbox, diagnose. Stage 1, Select, selects: reputable upstreams, official CLIs, narrow use cases. Stage 2, Wrap, wraps: descriptor, pinned runtime, ToolHive policy. Stage 3, Validate, tests: install smoke, schema checks, permission tests. Stage 4, Expose, exposes: default catalog, user approval, diagnostics.] *Curated Default Capability Chain: a capability is selected, wrapped, validated, and only then exposed as a default.* ## Curation is a security decision An open plugin market is a supply-chain attack surface. Any package an agent can install on its own is a package that could read your files, steal credentials, or drive a browser with your privileges. Asking a user to vet each one defeats the point of automation. So Ambient curates the defaults. The capabilities that show up ready to install are chosen from reputable upstreams, wrapped in reviewed descriptors, pinned to specific runtimes, and isolated with ToolHive. You can still add your own, but the common path does not require you to trust a stranger's code. ## The curated default catalog These are the kinds of capabilities Ambient surfaces as reviewed defaults. Each is a known, reputable upstream wrapped behind a pinned descriptor and permission policy. The Plugin Manager is where they appear: curated defaults, install state, and each capability's trust boundary. ### Scrapling Public web extraction that adapts between fetch-based and browser-based scraping. Runs inside ToolHive because any page can be hostile. ### Context7 Up-to-date library and framework documentation lookup, so the agent grounds answers in current docs. ### Search A reviewed web-search provider returns candidate sources and snippets, which the agent can then read with a fetch or browser capability. ### Browser surfaces First-party, policy-bounded browser capabilities for rendering, login state, and screenshot evidence where extraction is not enough. > [!WARNING] Container runtime required > ToolHive-backed capabilities such as Scrapling need a container runtime > (Docker, Podman, or equivalent) installed and running. Core Setup checks > for it and routes you through recovery if it is missing. ## How a default earns its place A capability does not become a one-click default until it has passed a deliberate pipeline. The same pipeline is what makes the defaults safe to trust. ### 1. Select Start from a reputable upstream or official CLI with a narrow, well-understood use case, not an arbitrary community package. ### 2. Wrap Express it as a descriptor with a pinned runtime version and a ToolHive permission profile, so what it can do is explicit. ### 3. Validate Run install smoke tests, schema checks, and permission tests in release gates before it ships as a default. ### 4. Expose Only then does it appear in the default catalog, still behind user approval and with diagnostics and an uninstall path. ## Scrapling, end to end Scrapling is a good example of the whole philosophy. Agents genuinely need web extraction, and Scrapling is good at it, which is exactly why it is risky, because extraction means loading pages an agent chose, not a human. Ambient ships it as a reviewed default, installs it through a pinned descriptor, runs it as a ToolHive-managed workload, and still keeps individual tool calls permissioned. You get the capability without handing arbitrary pages a foothold on your machine. ## FAQ **Can I still install things that are not curated?** Yes. Custom MCP servers, Pi packages, and capabilities you build yourself are all supported. Curation governs the defaults, not your ceiling. Riskier additions just go through privileged review. **How is this validated?** The curated catalog is covered by validation commands like `validate:curated-marketplace` and `test:mcp-default-catalog`, which check descriptors, schemas, and permission behavior. ## Keep going - [Security model](https://ambient.xyz/docs/use/desktop/security): how a contained capability actually runs, and where the boundary is drawn - [Browser and scraping safety](https://ambient.xyz/docs/use/desktop/browser-scraping): the policy around the web capabilities in this catalog - [Plugins and marketplace](https://ambient.xyz/docs/use/desktop/plugins): the four install classes and the Capability Builder --- # Browser and scraping safety > Ambient Desktop treats every fetched page as untrusted input. URL policy, private-address protection, isolated runtimes, bounded outputs, and visible approval bound what a web capability can do. - Canonical: https://ambient.xyz/docs/use/desktop/browser-scraping --- Letting an agent browse the open web means letting it load pages a human never vetted. Ambient Desktop treats every page as untrusted: powerful web capabilities, bounded by policy, isolation, and visible approval. Risky capabilities are sandboxed so the agent can operate on a regular desktop with bounded authority; the [security model](https://ambient.xyz/docs/use/desktop/security) covers that boundary in full. ## Every page is untrusted input When you browse, you decide what to click. When an agent browses, it follows links and renders pages on its own, including pages chosen by search results, redirects, or the content of other pages. That makes the open web an untrusted input channel: a hostile page can try to exfiltrate data, reach internal network addresses, or steer the agent through injected instructions. Ambient's answer is to never treat a fetched page as trusted code. Browser and scraper capabilities run with explicit policy, address protection, and isolation, and anything sensitive surfaces an approval rather than happening quietly. The sandbox boundary is four stages between a hostile page and your machine: [Diagram: Capability Sandboxing Model, the sandbox boundary: policy, isolation, audit. Stage 1, Untrusted surface, classifies risk: an MCP server, a Pi package, a browser page, or a scraper. Stage 2, Ambient mediation, applies policy: descriptor review, permission policy, secret redaction, ToolHive. Stage 3, Execution boundary, contains execution: container workload, sandboxed Pi tool, URL policy, audit log. Stage 4, User proof, proves outcome: prompted approval, visible output, diagnostics, rollback.] *Capability Sandboxing Model: a risky capability is classified, mediated by policy, contained at execution, and then proved to you.* ## The risks, and the bounds | Risk | Bound | What it does | | --- | --- | --- | | Reaching inward | **Private-address protection** | Requests to localhost and private network ranges are a separate, gated boundary, so a public task cannot quietly pivot to internal services | | Hostile content | **URL policy & isolation** | Browsing and extraction run with URL policy inside isolated runtimes (Scrapling via ToolHive), so a malicious page is contained, not trusted | | Data exposure | **Bounded outputs** | Large page content is kept as artifacts with bounded previews, and secrets are redacted from what the agent and logs see | | Silent action | **Visible approval** | Sensitive steps (logged-in browsing, downloads, form submission) require a visible permission grant with a clear scope | ## Extraction first, browser when needed Most web tasks do not need a full browser. Ambient prefers the lightest capable tool and escalates only when the page demands it: search finds candidate sources, [Scrapling](https://ambient.xyz/docs/use/desktop/curated-defaults) extracts content from public pages, and a full browser session is used when rendering, login state, or screenshots actually matter. This keeps the attack surface as small as the task allows. The [provider routing](https://ambient.xyz/docs/use/desktop/provider-routing) page covers how that escalation is configured and recorded. ## What you get back is evidence Because the web is untrusted, Ambient returns proof rather than assurances. A browsing or scraping step leaves screenshots, logs, and source attribution you can inspect, so you can judge whether the result is real, see which pages were touched, and confirm nothing sensitive leaked. Those artifacts land in the evidence panels of the main Ambient Desktop shell, which combines chat, workspace context, navigation, and evidence in one local developer workstation. Evidence is the point: it is how you verify an autonomous web task without having watched it. ## FAQ **Can the agent access my internal network?** Local and private-address access is a separate approval boundary. Public web tasks do not get it implicitly; reaching internal services requires crossing that boundary explicitly. **Do I need a browser for every web task?** No. Search and Scrapling extraction handle most public-page work. A full browser session is reserved for cases that need rendering, authenticated state, or screenshots. **How do I know what a page returned?** Web steps produce inspectable evidence (screenshots, logs, and source attribution) with secrets redacted, so you can verify the result instead of trusting a summary. ## Keep going - [Security model](https://ambient.xyz/docs/use/desktop/security): how risky capabilities are contained while the desktop stays usable - [Curated defaults](https://ambient.xyz/docs/use/desktop/curated-defaults): the reviewed web capabilities, and why they are pinned and sandboxed - [Provider routing](https://ambient.xyz/docs/use/desktop/provider-routing): prioritizing and falling back through search, fetch, and browser providers --- # Privacy and data retention > Ambient's zero-data-retention guarantee. What is enforced today on testnet, and what onion routing and end-to-end encryption add on mainnet. - Canonical: https://ambient.xyz/docs/use/desktop/privacy --- When Ambient Desktop, or any other client, sends an inference request to the Ambient network, the network keeps no user data beyond what is needed to serve and bill the request. Ambient serves and bills the request, then retains nothing, and on testnet that is verified two independent ways, by technical inspection and by legally binding contract. How the guarantee is enforced, and which further privacy capabilities are available, depends on the network stage. [Diagram: A two-zone diagram split by the boundary of your machine. The left zone, labelled your machine and local-first, lists what stays on your device: files and workspace, secrets held in managed flows, sandboxed capabilities, and agent memory which is off by default. An arrow labelled request crosses to the right zone, and an arrow labelled response returns. The right zone, labelled Ambient network and zero data retention, shows three steps: serve the request in memory then release it, return the response, and discard the content with no store and no log. Below a divider it notes that only usage and billing metadata is kept, never the content you sent or received.] *Local-first on your side of the line, zero data retention on the network's: your files, secrets, and workspace stay on your machine, and what does reach Ambient is served in memory and then discarded. Only usage and billing metadata is kept.* ## Zero data retention by default Ambient is **zero-data-retention (ZDR) by default**. As a provider, Ambient does not keep: - your prompts, - your files and context, - your tool inputs, - the model's outputs. Requests are processed in memory to produce a response and are then discarded. The only thing retained is the minimum required to **serve and bill** a request: usage metering such as request counts, plus billing metadata. Your content is never part of that record. ## What "serve and bill" actually covers Two narrow purposes, and nothing beyond them. | Purpose | What it means | | --- | --- | | **Serve**: fulfilling the request | Your prompt and context are processed transiently to produce a response, then released. There is no content store, no training corpus, and no retained conversation log on Ambient's side | | **Bill**: metering usage | The metadata needed to count and bill requests is kept: usage totals, not the content of what you sent or received | ## How the guarantee is enforced today (testnet) The Ambient chain is on [testnet](https://ambient.xyz/docs/learn/testnet) today, and the enforcement mechanism is scoped to that stage: the infrastructure that serves requests is **whitelisted**, and it fully meets the zero-data-retention guarantee. That is verified in two independent ways, so it is not only a promise in a document: | Check | What it establishes | | --- | --- | | **Technical inspection** | The whitelisted serving infrastructure can be inspected to confirm that no user content is retained | | **Legally binding contracts** | The same guarantee is backed by binding contractual commitments, so the obligation is enforceable rather than aspirational | ## On the roadmap for mainnet Two further privacy capabilities are tied to mainnet rather than testnet. Both are labelled roadmap here so that what is and is not available today is explicit. > [!WARNING] Roadmap: not available on testnet > Neither onion routing nor end-to-end encryption is offered on testnet today. > Both arrive with mainnet. - **Onion-routed requests** are not offered on testnet: it is too small on a per-server basis to onion-route requests credibly. Onion routing will be available on mainnet. - **End-to-end encryption** will be available upon request for mainnet customers. ## Local-first, on top of zero retention Provider-side ZDR pairs with how the desktop already works. Ambient Desktop is local-first: your files, workspace, and secrets stay on your machine, risky capabilities are sandboxed (see the [security model](https://ambient.xyz/docs/use/desktop/security)), and provider keys move through managed secret flows rather than into chat. Zero data retention covers what reaches the provider; the security model covers what stays on your device. Even the experimental [agent memory](https://ambient.xyz/docs/use/desktop/agent-memory) system is workspace-local and off by default. ## Read the full policy This is a plain-language summary. Ambient's complete privacy and data policies, with the precise definitions, scope, and terms, are published at [ambient.xyz](https://ambient.xyz). If your deployment has specific compliance requirements, start there. ## FAQ **Do you store my prompts or the model's responses?** No. Prompts, context, tool data, and outputs are processed in memory to serve the request and then discarded. Only usage and billing metadata are retained. **How is zero data retention verified?** On testnet, the serving infrastructure is whitelisted and meets the guarantee, confirmed by both technical inspection and legally binding contracts. **Is onion routing or end-to-end encryption available now?** Not on testnet. Onion routing is coming on mainnet (testnet is too small per server to do it credibly), and end-to-end encryption will be available on request for mainnet customers. **Where can I read the binding policy?** The full privacy and data policies are published at ambient.xyz. ## Keep going - [Security model](https://ambient.xyz/docs/use/desktop/security): the agent works on your real desktop; the genuinely risky capabilities are what gets contained - [Agent memory](https://ambient.xyz/docs/use/desktop/agent-memory): the opt-in, experimental system that reuses relevant context across turns, adapted from the open-source TencentDB-Agent-Memory project, stored workspace-local, and off by default - [Provider routing](https://ambient.xyz/docs/use/desktop/provider-routing): prioritizing and falling back through providers for search, fetch, browser, media, and model-adjacent work --- # Network client > Ambient Desktop is growing into a first-party client for the Ambient network, with wallet, balances, programs, and transaction evidence. This surface is in active development. - Canonical: https://ambient.xyz/docs/use/desktop/network-client --- Ambient Desktop is growing into a first-party client for the Ambient network: embedded keys, balances, programs, and transaction evidence, with the same inspect-everything posture as the rest of the app. > [!WARNING] In development > This is direction, not a finished product. What exists in the desktop app > today is the foundation: an Ambient blockchain CLI package descriptor and > skill, and the permissioned-capability machinery that network operations > will run through. Live wallet flows, program deployment, and on-network > transactions from the app are still being built. ## Why the desktop is the client Network operations have the same shape as the agentic work the app already does: authorize a capability, perform an action, observe the result, and keep durable evidence of what happened. Rather than ship a separate tool, Ambient is extending the workstation so a developer can move from code work to network work without changing mental models: inspect state, approve the action, capture the receipt. [Diagram: A four-stage chain for a network operation, bounded as permissioned, reviewable, with durable evidence. Stage one, Authorize a capability: descriptor review and a permission policy. Stage two, Perform the action: wallet and programs, via the Ambient L1 CLI. Stage three, Observe the result: transaction observation with logs and receipts. Stage four, Evidence kept durable: receipts and a rollback plan.] *Network operations have the same shape as the agentic work the app already does, so the desktop runs them the same way: authorize a capability, perform the action, observe the result, and keep durable evidence at each step.* ## What the client is being built to do - **Wallet workbench**: embedded key flow, balances, and approvals, presented through the same permissioned, reviewable surfaces as other capabilities. - **Programs**: deploy, observe, and update programs with the agent assisting, and evidence captured at each step. - **Ambient L1 CLI**: an Ambient blockchain CLI package descriptor and skill provide the building blocks for network operations, exposed as a permissioned capability. - **Receipts and rollback**: transaction observation, receipts, logs, and a rollback plan, consistent with how the app treats all high-impact actions. Desktop integration of the [Tool Oracle](https://ambient.xyz/docs/build/tool-oracle) and of [x402](https://ambient.xyz/docs/build/x402) payments is roadmap direction. x402 is live on the network today: the API accepts pay-per-use payments in USDC on Solana and Base. ## Frequently asked **Can I do on-chain transactions in the app today?** Not yet. The Ambient L1 CLI package descriptor and skill are available today as building blocks, but live wallet and transaction flows are still in active development. **Will network operations be sandboxed like other capabilities?** Yes. The intent is that network capabilities run through the same descriptor review, permission policy, and audit-artifact model as the rest of the app, with keys and approvals kept in managed, reviewable surfaces. See the [security model](https://ambient.xyz/docs/use/desktop/security). ## Keep going - [Local models and routing](https://ambient.xyz/docs/use/desktop/local-models): how the app routes work across local and network models - [Mini Miner](https://ambient.xyz/docs/mine/mini-miner): the planned opt-in local mining path this client direction supports --- # Local models and routing > How Ambient Desktop routes work across local llama.cpp runtimes, network models, and cloud providers, keeping private, cheap, or latency-sensitive work on your machine. - Canonical: https://ambient.xyz/docs/use/desktop/local-models --- Ambient Desktop chooses between local and remote models for each step of a task, keeping private, cheap, or latency-sensitive work on your machine. > [!WARNING] In development > The runtime lifecycle, local-first selection, and vision routing are real > today; broader routing across the Ambient network and the future Ambient > Mini layer is still being built. ## One task, the right model A single model is rarely the right answer for every step of a task. Summarizing a private file, analyzing a screenshot, and reasoning through an architecture trade-off have different needs for privacy, latency, cost, and capability. Ambient Desktop treats the model layer like its provider layer: an ordered set of runtimes that can be selected and retried by what the task actually needs. Not every task should leave your machine. [Diagram: A routing diagram. On the left, one step of a task (summarize, look, or reason) flows into a central Router node in the middle. The router is ordered and retryable, and you can prioritize local-first, disable a provider, or inspect its evidence. From the router, four arrows fan out to the runtime classes it can choose by task fit: a local llama.cpp runtime for private, cheap, or offline work; a local MiniCPM-V vision runtime where pixels stay on device; heavy reasoning on cloud or network models such as Ambient; and the planned Ambient Mini local-model network layer.] *Ambient Desktop treats the model layer like its provider layer: each task step enters an ordered, retryable router that picks the runtime the step actually needs: local, local vision, heavy cloud or network reasoning, or the planned Ambient Mini layer.* ## What can route where - **Local runtimes**: llama.cpp-hosted models with non-destructive start/stop lifecycle management, for private, low-cost, or offline-friendly work. - **Vision, locally**: a local MiniCPM-V runtime so screenshots and images can be understood even when the selected text model has no native vision. See [Local visual analysis](https://ambient.xyz/docs/use/desktop/visual-analysis). - **Heavy reasoning**: high-capability cloud and network-native models (Ambient or another selected provider) for the hard synthesis steps a small local model should not own. - **Ambient Mini (planned)**: a local-model network layer where eligible machines serve and earn, built on this same runtime foundation. See [Mini Miner](https://ambient.xyz/docs/mine/mini-miner). ## Controls you have - Prioritize local-first, fastest, most private, cheapest, or most capable providers. - Disable a provider entirely so it never receives a class of content. - Inspect fallback and skip evidence to see why a given runtime was or was not used. - Repair or revalidate local runtimes from Settings when assets or binaries drift. ## Frequently asked **How is this different from [provider routing](https://ambient.xyz/docs/use/desktop/provider-routing)?** Provider routing covers search, fetch, browser, and vision capabilities; local model routing is the model layer specifically. They share the same idea: an ordered, retryable set chosen by preference and task fit. **Do I need a powerful machine?** Local runtimes scale with your hardware. You can keep heavy reasoning in the cloud and use local models for private, cheap, or vision tasks, or run more locally on capable machines. ## Keep going - [Local visual analysis](https://ambient.xyz/docs/use/desktop/visual-analysis): the local vision bridge in detail - [Agent memory](https://ambient.xyz/docs/use/desktop/agent-memory): local embeddings run on the same managed runtime - [Mini Miner](https://ambient.xyz/docs/mine/mini-miner): the planned network layer on top of local hosting --- # Plugins and marketplace > How Ambient Desktop extends safely. Four install classes with visible permissions, the Plugin Manager, a Capability Builder for custom tools, and a curated marketplace direction. - Canonical: https://ambient.xyz/docs/use/desktop/plugins --- Every way Ambient Desktop gains a new tool falls into one of four install classes, each with a visible permission profile and an uninstall path; a Capability Builder covers jobs the catalog does not. The marketplace direction is curated and legible, not a raw feed of arbitrary executable code. > [!NOTE] Developer Preview > Plugins, the Plugin Manager, and the Capability Builder ship as a > Developer Preview: substantial implementation and tests exist, and edge > cases are still being proven. See [maturity > labels](https://ambient.xyz/docs/resources/maturity-labels). ## How capabilities stay accountable Plugins are how an agent grows, and how supply-chain risk usually enters one. Ambient Desktop's answer is legibility: every capability has a known class, the permissions it runs under are visible, and you can inspect, validate, repair, and remove it. The Plugin Manager is where that state lives. The marketplace is curated: a default capability is selected, described, pinned, sandboxed, and validated before it becomes an easy install path. [Curated defaults](https://ambient.xyz/docs/use/desktop/curated-defaults) covers that catalog and the pipeline behind it. ## The install classes What you can add falls into four classes, ordered by how much trust each one asks for. The class tells you how it is contained. [Diagram: Four install-class columns ordered left to right by how much trust each asks for, rising like a ladder. Curated defaults: reviewed MCP capabilities with a ToolHive runtime, contained by being pinned and sandboxed. Pi packages: sandboxed tools for one job, with no privileged host access. Custom MCP servers: your own server by descriptor, contained by a one-time trust prompt and an MCP permission policy. Privileged packages: anything wanting lifecycle hooks, native dependencies, or host mutation, contained by explicit privileged review. An axis beneath runs from lowest friction to highest review.] *Every install class carries a visible permission profile. They line up by how much trust each asks for (from curated defaults at lowest friction to privileged packages at highest review), and each shows how it is contained.* | Class | What it is | How it is contained | | --- | --- | --- | | **Curated defaults** (lowest friction) | Reviewed MCP capabilities with ToolHive runtime boundaries, the safe common path, covered in [curated defaults](https://ambient.xyz/docs/use/desktop/curated-defaults) | Pre-vetted, pinned, and sandboxed; still installed behind user approval, with diagnostics and an uninstall path | | **Pi packages** (narrow tools) | Sandboxed, tool-shaped extensions for a specific job | Kept separate from privileged host access | | **Custom MCP servers** (bring your own) | Your own MCP server by descriptor: command, args, environment | First use triggers a one-time trust prompt, then it runs under an MCP permission policy | | **Privileged packages** (highest review) | Anything wanting lifecycle hooks, native dependencies, or host mutation | Explicit privileged review before it runs | Custom MCP servers and privileged packages run under an MCP permission policy after their trust prompt; you can see and change that policy, and uninstall the plugin, from the Plugin Manager. How those policies are enforced at runtime is the [security model](https://ambient.xyz/docs/use/desktop/security). ## The Plugin Manager The Plugin Manager is the single surface for installed capability state: the curated defaults, what is installed, and where each capability's trust boundary sits. Per capability you can: - Read the permission policy it runs under, and change it. - Preview and validate it before you depend on it. - Repair a broken install, update it, or re-register it after a change. - Remove it. ## Build your own capability When the catalog does not cover a narrow, repeatable job, the Capability Builder turns it into a first-class capability instead of a brittle prompt. You describe: - the provider it wraps, - its locality: local, network, or either, - the outputs you expect, - any secrets it needs. Ambient turns that into an installer-friendly descriptor. Generated capabilities expose their command contract, dependency approvals, and secret requests up front; they can be previewed, validated, repaired, updated, re-registered, and removed from the Plugin Manager; and they run under the same MCP permission policy as any other capability. Building it yourself earns it no special trust. ### Worked example: a Hacker News digest Suppose you want a repeatable way to see the front page of Hacker News without re-typing the request each time. Turn it into a capability once, then call it whenever you like. ### 1. Describe it in Plugin Setup Open Plugin Setup, choose **Create capability**, and describe the job in plain language: ```text Create a skill that captures the top stories on Hacker News and prints them for the user. ``` ### 2. Set the contract Mark it as a network capability (it reads a public site), declare the output (a ranked list of titles, points, and links), and confirm it needs no secrets. Ambient turns that into an installer-friendly descriptor. ### 3. Review the generated descriptor Before anything runs, the descriptor shows its command contract, any dependency approvals, and that it requests no credentials. Reading a public page still passes through the same permission and isolation boundaries as any other capability. See [browser and scraping safety](https://ambient.xyz/docs/use/desktop/browser-scraping). ### 4. Validate once Run it a single time to confirm the output shape. You should get the current top stories with their titles, scores, and links: proof it works before you depend on it. ### 5. Invoke it anytime From then on, call it like any reviewed tool ("Run my Hacker News digest") and it prints the current front page. Update, re-register, or remove it from the Plugin Manager whenever you want. ## Where the marketplace is headed Today the experience is a curated catalog plus your own local additions. The roadmap is a hosted storefront for reviewed Web2 and Web3 capabilities built on Ambient, with signing, checksums, and provenance policy, so that breadth arrives without giving up the trust posture. > [!NOTE] Direction, not a shipped surface > The hosted storefront is roadmap direction. What ships today is the > curated catalog, custom MCP servers, Pi packages, privileged installs, > and the Capability Builder. ## FAQ **What happens the first time a plugin runs?** Custom and imported plugins trigger a one-time trust prompt and then run under an MCP permission policy. You can see and change that policy, and uninstall the plugin, from the Plugin Manager. **Can I add a plugin that is not in the catalog?** Yes. Import a custom MCP server by descriptor, or build one with the Capability Builder. It runs through trust and permission review rather than arriving pre-vetted. ## Keep going - [Curated defaults](https://ambient.xyz/docs/use/desktop/curated-defaults): the reviewed, sandboxed capabilities that cover the common path - [Security model](https://ambient.xyz/docs/use/desktop/security): how contained capabilities actually run - [Local visual analysis](https://ambient.xyz/docs/use/desktop/visual-analysis): a built-in capability that stays on your machine --- # Local visual analysis > Ambient Desktop routes screenshots and images to a MiniCPM-V vision model on your own machine, so text models without native vision can still see, no cloud round trip. - Canonical: https://ambient.xyz/docs/use/desktop/visual-analysis --- Ambient Desktop's local vision bridge lets a text model understand screenshots, images, and video frames without sending pixels to a cloud service. [Diagram: A four-stage chain for a look-at-this step in the local vision bridge, using MiniCPM-V so pixels stay on device. Stage one, Capture: a screenshot, image, or video frame enters as the visual input, for example proof a UI rendered. Stage two, Analyze locally on your machine: MiniCPM-V runs on a local llama.cpp runtime with no cloud endpoint. Stage three, Return to the text model: a structured tool result the model can reason about. Stage four, Repair if it fails: missing assets or a timeout are flagged by diagnostics that guide a fix.] *When a task needs to understand pixels, the image is routed to a MiniCPM-V model on your own machine and returns a structured result the text model can act on, no cloud round trip.* ## Vision without leaving your machine A coding agent needs to look at things (a screenshot of a failing UI, a diagram, a rendered page), but many strong text models have no native vision, and sending images to a cloud vision service is not always acceptable. Ambient Desktop bridges the gap locally: when a task needs to understand pixels, it routes the image to a MiniCPM-V model running on your own machine and returns structured observations the text model can act on. ## How a look-at-this step works ### 1. Capture An image, video frame, or screenshot enters as the visual input; for example, proof that a calculator actually rendered. ### 2. Analyze locally MiniCPM-V runs on a local llama.cpp runtime and produces a structured description; the image never goes to a cloud endpoint. ### 3. Return to the agent The structured result flows back to the text model as a tool result, so it can reason about what it saw and take the next step. ### 4. Repair if needed If the runtime is missing assets, times out, or returns invalid output, diagnostics flag it and guide a repair instead of failing silently. ## Platform support The local vision runtime ships with platform-appropriate acceleration. Heavier-accelerated platforms get it on by default; lighter ones are experimental. | Platform | Support | | --- | --- | | macOS (Apple Silicon) | Metal-accelerated; the local vision runtime is enabled by default | | Linux (x64) | Vulkan/CUDA acceleration; enabled by default on capable machines | | Windows (x64) | Experimental and CPU-only today, so analysis is slower; treat it as a preview path | ## Safety and repair - Local runtime checks surface missing binaries, absent model assets, timeouts, invalid structured output, and memory pressure, with guidance to fix each. - Hosted or remote visual endpoints are a separate, higher-risk path that requires explicit security review before they are enabled. - Local visual analysis is a routing building block: it lets local-first operation include vision without forcing every screenshot to the cloud. ## Keep going - [Local models and routing](https://ambient.xyz/docs/use/desktop/local-models): how vision fits into per-task model selection - [Security model](https://ambient.xyz/docs/use/desktop/security): why remote endpoints are gated harder than local ones --- # Agent memory > An experimental, opt-in memory system that recalls and captures context across turns, stored workspace-local in SQLite, off by default, inspectable and deletable. - Canonical: https://ambient.xyz/docs/use/desktop/agent-memory --- Agent memory is Ambient Desktop's experimental system for keeping useful context across turns and sessions. It is workspace-local, off by default, and fully inspectable. > [!WARNING] In development > Agent memory is experimental. It is off by default, gated behind an > experimental flag and a Settings switch, and the store stays > workspace-local: nothing is synced to a cloud service in this phase. ## Memory that lives outside the transcript Chat context is fragile: once a conversation is trimmed or a session ends, what the agent "knew" is gone. Agent memory keeps useful context in a durable store instead. Before each turn it recalls what is relevant; after each turn it captures what happened, so later work builds on earlier work without you re-explaining. The engine is adapted from the open-source TencentDB-Agent-Memory project (TencentCloud), whose four-layer pipeline distills raw conversation into reusable facts, profiles, and task structure. Ambient Desktop wraps that engine behind its own host adapter, runs it workspace-local, and keeps it off by default while it is in development. ## How a turn uses memory Memory hooks into the agent loop at two points: a read before the model runs, and a write after it finishes. The store itself stays on your machine. [Diagram: Agent Memory Loop diagram. Each turn runs User message (the turn begins), Recall (search prior memory), Enriched prompt (context prepended), Assistant reply (the model responds), and Capture (record the turn). Recall reads from and Capture writes back to a workspace-local memory store: local SQLite plus optional vectors in .ambient, off by default, holding four layers L0 raw turns, L1 facts, L2 profiles, and L3 scenes.] *Agent Memory Loop: each turn recalls relevant prior context before the model answers, then captures the turn back into a workspace-local store.* ### 1. Recall, before the model answers When memory is enabled for a thread, Ambient Desktop searches the store for context relevant to your message and prepends a bounded set of matches to the prompt, capped in size so it informs the model without flooding it. ### 2. Respond The provider answers with that recalled context in view. Routing, approvals, and every other safeguard work exactly as they do without memory. ### 3. Capture, after the turn The completed turn is written back to the store as a raw record, and higher-level extraction distills it into structured memory for future recall. ## The four layers The adapted pipeline organizes memory into four layers, from raw conversation up to task structure. Higher layers make recall sharper than a plain transcript search. [Diagram: A four-layer memory stack, distilled from the bottom up. L0, Raw turns: the verbatim record of each exchange, the source of truth. L1, Facts: structured, reusable facts, so the agent recalls the point rather than the paragraph. L2, Profiles: longer-lived conversation and preference profiles. L3, Scenes: task- and scene-level structure for sharper, situation-aware recall. An axis on the left runs from raw at the bottom to distilled at the top.] *The adapted pipeline organizes memory into four layers, from the raw record at the base up to task-level structure: higher layers make recall sharper than a plain transcript search.* | Layer | What it holds | | --- | --- | | **L0: raw turns** | The verbatim record of each captured exchange; the source of truth everything else is derived from | | **L1: facts** | Structured, reusable facts extracted from conversation, so the agent recalls the point rather than the paragraph | | **L2: profiles** | Longer-lived conversation and preference profiles that persist across many turns | | **L3: scenes** | Task- and scene-level structure that ties related work together for sharper, situation-aware recall | ## Turning it on, staying in control Agent memory is experimental and off by default. You opt in deliberately, and you can scope it down to a single thread. - **Enable the system.** Memory is gated by an experimental flag and a Settings switch, so it never starts capturing anything until you turn it on. Settings search finds it alongside the other provider, permission, and runtime configuration. - **Per-thread control.** Each thread carries its own memory toggle. Keep most chats memoryless and enable memory only where continuity helps. - **Optional local embeddings.** Semantic recall can use a local embedding model run through Ambient Desktop's managed llama.cpp runtime, so it stays local-first and no content is sent to the cloud to be remembered. - **Inspect and delete.** Built-in tools let you search, inspect, edit, and delete stored memories from chat. Memory you can see is memory you can correct. ## Where your memories live Privacy is a design constraint here, not an afterthought. The store is workspace-local: a SQLite database (with optional local vectors) under the workspace's `.ambient` directory. It is not shared between workspaces and is not synced to a cloud service in this phase. Because you can list and delete entries, and because the whole system is opt-in, you stay in control of what is retained. ## What ships today, and what is still planned The local pipeline is functional today, behind the experimental flag: - Recall before a turn and capture after it. - The L0–L3 layers and the extraction that populates them. - Optional local-embedding semantic search. - Short-term offload of large tool outputs. - Inspect, edit, and delete for stored memories. Not here yet: - A cloud-backed vector store. - Memory shared across workspaces. - Graduation out of experimental status. The building blocks work today; memory stays opt-in and behind the flag until the system has proven itself, which is why it is not on by default. ## FAQ **Is memory on by default?** No. It is experimental and off by default, gated by a flag and a Settings switch, with a per-thread toggle on top. Nothing is captured until you opt in. **Does my conversation get sent somewhere to be remembered?** No. The store is workspace-local SQLite under `.ambient`, and semantic recall can run on a local embedding model. There is no cloud memory backend in this phase. **Can I see and remove what it remembered?** Yes. Built-in tools let you search, inspect, edit, and delete stored memories directly from chat, so you can audit and correct the store at any time. **How does this relate to durable goals?** [Durable goals](https://ambient.xyz/docs/use/desktop/durable-goals) persist the plan and evidence for one objective; agent memory persists reusable context across many turns and tasks. They complement each other. ## Keep going - [Durable goals](https://ambient.xyz/docs/use/desktop/durable-goals): persistence for a single long-running objective - [Local models and routing](https://ambient.xyz/docs/use/desktop/local-models): the runtime that powers optional local embeddings - [Privacy and data retention](https://ambient.xyz/docs/use/desktop/privacy): the local-first posture this system fits into - [Plugins and capabilities](https://ambient.xyz/docs/use/desktop/plugins): how other optional surfaces are gated and installed --- # Desktop API endpoints > The OpenAI-compatible inference API that Ambient Desktop and any other agent point at. Base URL, auth header, model IDs, and the endpoints you call. - Canonical: https://ambient.xyz/docs/use/desktop/api-endpoints --- Ambient's inference API is OpenAI-compatible. Point Ambient Desktop or any agent at one base URL, call the included model (or any model listed by `GET /v1/models`), and get zero-data-retention inference. [Get an API key](https://app.ambient.xyz/keys), or read the [full API reference](https://ambient.xyz/docs/build/api). ## One endpoint, any agent Ambient serves a standard, OpenAI-compatible inference API. If a tool can talk to OpenAI, it can talk to Ambient: change the base URL and the key, keep everything else the same. The same endpoint powers Ambient Desktop and any agent you already use, and every request is [zero data retention](https://ambient.xyz/docs/use/desktop/privacy). | Setting | Value | | --- | --- | | Base URL | `https://api.ambient.xyz/v1` | | Protocol | OpenAI Chat Completions compatible (Anthropic Messages format also supported) | | Auth header | `Authorization: Bearer ` | | API keys | [app.ambient.xyz/keys](https://app.ambient.xyz/keys) | | Data retention | Zero. See [Privacy and data retention](https://ambient.xyz/docs/use/desktop/privacy) | | Payments | Subscription plans ($1–$200), or pay-per-use via x402 on Solana and Base | ## Endpoints Two endpoints cover the OpenAI-compatible path used throughout this page. Both hang off the base URL above, so the full URLs are `https://api.ambient.xyz/v1/chat/completions` and `https://api.ambient.xyz/v1/models`. | Method | Path | What it is for | | --- | --- | --- | | `POST` | `/v1/chat/completions` | Inference. Send a `model` id and `messages`; add `"stream": true` for token streaming | | `GET` | `/v1/models` | List the models that are currently available to call | Field-level parameter and response references live in [Chat completions](https://ambient.xyz/docs/build/api/chat-completions) and [Models endpoint](https://ambient.xyz/docs/build/api/models-endpoint). The Anthropic Messages endpoints are served from the same base URL and are covered in the [API reference](https://ambient.xyz/docs/build/api). ## Get an API key ### 1. Sign up Create an account at app.ambient.xyz. ### 2. Create a key Generate an API key at app.ambient.xyz/keys and copy it somewhere safe; you send it as a Bearer token. ### 3. Keep it out of your code Set it as an environment variable (for example `AMBIENT_KEY`) rather than hard-coding it. In Ambient Desktop you simply sign in. The app manages the key for you. ## Models Pass the model ID as the `model` field. `GET /v1/models` is the source of truth for what is callable right now. | Model | Model ID | Status | | --- | --- | --- | | GLM 5.2 | `z-ai/glm-5.2` | Supported production model. Fast, capable, tuned for agentic coding and tool use | | Qwen3.6 27B | `qwen/qwen3.6-27b` | Preview. Served and callable, with no guarantees; may later be limited to specific partners | | Qwen3.8 27B | `qwen/qwen3.8-27b` | Preview. Served and callable, with no guarantees; may later be limited to specific partners | `ambient/large` is an Ambient-managed alias that always points at the current large model, so it keeps working across model upgrades. It resolves to GLM 5.2 today. See [Models](https://ambient.xyz/docs/build/models). Every model listed by `GET /v1/models` is served. The `is_ready` field in that response is a routing flag, not a liveness signal: a model can be listed, served, and answering with `is_ready: false`, so do not gate on it. ## Quickstart A first call in three flavors. Swap the model ID to switch models, and add `"stream": true` (or `stream=True`) for token streaming. ```bash title="curl" curl https://api.ambient.xyz/v1/chat/completions \ -H "Authorization: Bearer $AMBIENT_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ambient/large", "messages": [{"role": "user", "content": "Say hello from Ambient."}] }' ``` ```python title="Python (openai SDK)" from openai import OpenAI client = OpenAI( base_url="https://api.ambient.xyz/v1", api_key="YOUR_AMBIENT_KEY", # create one at https://app.ambient.xyz/keys ) resp = client.chat.completions.create( model="ambient/large", # alias for "z-ai/glm-5.2" messages=[{"role": "user", "content": "Say hello from Ambient."}], ) print(resp.choices[0].message.content) ``` ```javascript title="Node (openai SDK)" import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.ambient.xyz/v1", apiKey: process.env.AMBIENT_KEY, // create one at https://app.ambient.xyz/keys }); const resp = await client.chat.completions.create({ model: "ambient/large", messages: [{ role: "user", content: "Say hello from Ambient." }], }); console.log(resp.choices[0].message.content); ``` ```bash title="List available models" curl https://api.ambient.xyz/v1/models ``` ## Use it from your agent of choice ### Ambient Desktop Built in. Sign in once and the included model is ready. Nothing to configure. Start with the [Quickstart](https://ambient.xyz/docs/use/desktop/quickstart). ### Any OpenAI-compatible tool Editors, agent frameworks, and SDKs that accept a custom OpenAI base URL just work: set the base URL to `https://api.ambient.xyz/v1` and your Ambient key. ### Claude Code and Anthropic SDK Ambient also speaks the Anthropic Messages format. See the [Claude Code setup](https://ambient.xyz/docs/build/claude-code) and the [Anthropic SDK guide](https://ambient.xyz/docs/build/anthropic-sdk) for exact configuration. ## Zero data retention Every request through this API is zero data retention by default. Prompts, context, and outputs are processed to serve the response and then discarded. Only usage and billing metadata is kept. The guarantee is backed by both technical inspection and legally binding contracts. See [Privacy and data retention](https://ambient.xyz/docs/use/desktop/privacy) for the full story. ## Pay-per-use with x402 Beyond subscriptions, Ambient supports the x402 payment standard on Solana and Base, so agents can pay for inference per request. See the [x402 client documentation](https://ambient.xyz/docs/build/x402) for integration details. ## FAQ ### Is it really OpenAI-compatible? Yes. It implements the standard Chat Completions API, so any OpenAI client works by pointing its base URL at `https://api.ambient.xyz/v1` and using your Ambient key. The Anthropic Messages format is also supported. ### Which models can I call? GLM 5.2 (`z-ai/glm-5.2`) and the `ambient/large` alias that resolves to it. Qwen3.6 27B (`qwen/qwen3.6-27b`) and Qwen3.8 27B (`qwen/qwen3.8-27b`) are also served as a preview, with no guarantees. Call `GET /v1/models` to list what is currently available. ### Why does one message produce more than one request in Usage History? Because Ambient Desktop is an agent, not a plain chat. When a task needs a tool — reading a file, running a command, searching — Desktop sends a first request, the model asks for the tool, Desktop runs it locally, then sends a second request carrying the tool's output so the model can finish the answer. Each of those round trips is its own API request, and the later ones carry a larger prompt because the conversation so far travels with them. A plain chat turn in the web app answers in a single request, which is why the same question can look different in Usage History depending on where you asked it. Every request is billed on its own tokens, so an agent turn costs more than a single chat turn for the same question — you are paying for the extra context and the tool round trip, not for a different model. The model and the network are the same either way. ### Do you keep my prompts or responses? No. The API is zero data retention by default; only usage and billing metadata is retained. See [Privacy and data retention](https://ambient.xyz/docs/use/desktop/privacy). ### Where is the complete API reference? Every operation, with parameters and response fields, is in the [API reference](https://ambient.xyz/docs/build/api). This page is a quickstart for using Ambient inference from Ambient Desktop or your own agent. ## Keep going - [Privacy and data retention](https://ambient.xyz/docs/use/desktop/privacy): Ambient is zero-data-retention by default. No user data is kept beyond what is needed to serve and bill your requests, backed by technical inspection and legally binding contracts. - [Provider routing](https://ambient.xyz/docs/use/desktop/provider-routing): Ambient can prioritize and fall back through providers for search, fetch, browser, media, and model-adjacent work. - [Quickstart](https://ambient.xyz/docs/use/desktop/quickstart): start in the Welcome Folder, finish setup, then run a small calculator task with visible proof. --- # Ambient Desktop vs Codex CLI > Both ship a coding agent, so the comparison turns on form factor. A terminal-native loop versus a desktop workspace with persistent plans, sandboxed capabilities, and reviewable evidence. - Canonical: https://ambient.xyz/docs/use/desktop/comparisons/codex-cli --- Both are coding agents. Codex CLI lives in your terminal; Ambient Desktop wraps a coding agent in a durable, inspectable workstation that combines chat, workspace context, navigation, and evidence panels in one local window. ## The short version Codex CLI is a focused, terminal-native coding agent, fast to reach for inside an existing shell workflow. Ambient Desktop includes a coding agent too, but surrounds it with a workspace: a Project Board, durable goals, provider routing, sandboxed capabilities, browser evidence, and Git review. If you want a lightweight terminal loop, a CLI is great. If you want long-running work you can pause, inspect, and trust, that is what Ambient is built for. ## Feature comparison | Dimension | Ambient Desktop | Codex CLI | | --- | --- | --- | | Form factor | Desktop app with a full GUI (macOS, Windows, Linux) | Command-line agent in your terminal | | Work surface | Project Board, durable goals, artifact previews, Git review | Chat-style turns and file edits in the terminal | | Long-running work | Plan and evidence persist across restarts | Scoped to the terminal session | | Multiple agents | Symphony orchestrates scoped child agents with budgets and joins | Single agent loop | | Capability isolation | ToolHive containers, permission policy, secret redaction | Approval modes and an OS-level sandbox around the agent process | | Web and browser | Search → fetch → browser fallback with evidence | Depends on configured tools | | Local models | Local-first routing (llama.cpp, MiniCPM-V vision) | Any OpenAI-compatible provider you configure, typically a hosted API | | Extensibility | Curated MCP catalog, Pi packages, Capability Builder | MCP and tool config via the CLI | The isolation row is the architectural difference worth understanding. Codex CLI bounds the agent process; Ambient bounds the individual capability, which is why its agent keeps direct access to your real files and terminal while third-party MCP servers, scrapers, and browsers run contained. See the [security model](https://ambient.xyz/docs/use/desktop/security). ## When to choose which ### Reach for Codex CLI when - You live in the terminal and want a quick edit-and-run loop. - The task is small, single-session, and easy to eyeball. - You are scripting an agent into existing shell automation. ### Reach for Ambient when - Work spans many steps, files, or sessions and must survive restarts. - You want to review evidence before trusting a result. - You need sandboxed web/browser/MCP capabilities and provider routing. - You want to delegate to specialist sub-agents with Symphony. ## Keep going - [Project Board](https://ambient.xyz/docs/use/desktop/project-board): goals become durable plans, task cards, source-backed evidence, and review loops - [Security model](https://ambient.xyz/docs/use/desktop/security): why the capability gets contained instead of the agent - [Ambient Desktop vs Hermes](https://ambient.xyz/docs/use/desktop/comparisons/hermes): the same questions asked of an always-on messaging agent --- # Ambient Desktop vs Hermes > Both extend through MCP, so the comparison turns on where the agent lives. Always-on autonomy reachable from messaging platforms versus a local desktop workstation you drive and inspect. - Canonical: https://ambient.xyz/docs/use/desktop/comparisons/hermes --- Hermes is an always-on autonomous agent that lives across messaging platforms. Ambient Desktop is a hands-on, local-first workstation. They share an MCP foundation and a clear docs shape, but optimize for different work. Ambient's shell combines chat, workspace context, navigation, and evidence panels in one local window. ## Two different jobs Hermes (from Nous Research) is built to be an autonomous agent you talk to across messaging platforms (Nous documents 20+ of them), an assistant that runs continuously and grows more capable over time. Ambient Desktop is built to sit in front of you and do hands-on work on your own machine, where you can open the plan, the diff, and the screenshot behind every result. Both extend through MCP and both publish machine-readable docs. The difference is the center of gravity: messaging-native autonomy versus an inspectable desktop workstation. ## Feature comparison | Dimension | Ambient Desktop | Hermes | | --- | --- | --- | | Primary surface | Local desktop workstation | Autonomous agent across 20+ messaging platforms | | Where it runs | Your machine (local-first) | VPS, cloud, or serverless deployment | | Core use case | Coding, research, and browser work with reviewable proof | Always-on assistant that gets more capable over time | | Work visibility | Project Board, diagrams, Git review, screenshots | Conversational, with tools and memory | | Durability | Durable goals and board cards persisted to disk | Persistent agent memory | | Multiple agents | Symphony parent/child orchestration | Single autonomous agent | | Capability safety | ToolHive isolation, permission prompts, audit artifacts | Tool-level controls | | Extensibility | Curated MCP defaults + Pi packages + Capability Builder | 60+ built-in tools plus MCP | | Machine-readable docs | Full docs exported as plain text for LLMs | Full docs exported as plain text for LLMs | ## Where each shines ### Hermes is great when - You want an always-on agent reachable from chat apps. - The agent should run unattended on a server and accrue memory. - Messaging-platform reach matters more than a local GUI. ### Ambient is great when - You want to drive the work and review evidence as it happens. - Tasks touch local files, browsers, and source control. - You need sandboxed capabilities and provider routing you control. ## Keep going - [Symphony](https://ambient.xyz/docs/use/desktop/symphony): parent and child agents with scoped tools, role policy, artifacts, and join logic - [Project Board](https://ambient.xyz/docs/use/desktop/project-board): goals become durable plans, task cards, source-backed evidence, and review loops - [Ambient Desktop vs Codex CLI](https://ambient.xyz/docs/use/desktop/comparisons/codex-cli): the same questions asked of a terminal-native coding agent --- # Ambient Desktop vs open marketplaces > The comparison turns on default trust posture. An open feed of community plugins versus a curated, sandboxed default set that you extend deliberately. - Canonical: https://ambient.xyz/docs/use/desktop/comparisons/openclaw --- Open-marketplace agent platforms (the OpenClaw model) win on raw breadth. Ambient optimizes for trustworthy defaults and bounded risk, and you can still add anything you want, deliberately. The Plugin Manager is where that shows up: curated defaults, install state, and each capability's trust boundary in one place. ## Breadth versus trust Open agent marketplaces (the OpenClaw model) let you install almost anything from a large community feed. That is powerful, and it is also where supply-chain risk lives: a single unreviewed plugin can read files, exfiltrate secrets, or drive a browser with your privileges. Ambient takes the opposite default. Core capabilities come from a curated, reviewed, pinned set, and risky ones run inside containers behind permission policy. You give up nothing important: custom MCP servers, Pi packages, and your own capabilities are all still available. You just add them on purpose, with the trade-offs visible. ## How the models compare | Dimension | Ambient Desktop | Open-marketplace agents | | --- | --- | --- | | Default capabilities | Curated, reviewed, pinned defaults | Large open feed of community plugins | | Supply-chain posture | Reputable upstreams, descriptor review, pinned runtimes | Install-anything; trust is on the user | | Isolation | ToolHive containers + permission policy | Often runs with host or agent privileges | | Secrets | Ambient-managed secret flow with redaction | Varies by plugin | | Visibility | Install state, permissions, diagnostics, uninstall | Varies widely | | Extending further | Add custom MCP, Pi tools, and built capabilities deliberately | Add from the open marketplace | | Optimized for | Trustworthy defaults and bounded risk | Maximum breadth and novelty | ## The honest trade-off If your priority is the widest possible catalog and you are comfortable vetting each addition yourself, an open marketplace will feel more expansive. If you want capabilities you can hand to an autonomous agent without auditing every line first, Ambient's curated-and-sandboxed default is the safer foundation, and it scales up as the curated catalog and Capability Builder grow. ## Keep going - [Curated defaults](https://ambient.xyz/docs/use/desktop/curated-defaults): the small set of reputable, reviewed, sandboxed capabilities that ship on by default - [Security model](https://ambient.xyz/docs/use/desktop/security): how contained capabilities actually run - [Plugins and marketplace](https://ambient.xyz/docs/use/desktop/plugins): the install classes, visible permission profiles, and the Capability Builder --- # Build on Ambient > The Ambient API surface for developers. OpenAI-compatible chat completions and Anthropic-compatible messages at one base URL, with bearer-key auth. - Canonical: https://ambient.xyz/docs/build --- Ambient exposes a single HTTP API at `https://api.ambient.xyz` that serves open models running on the Ambient network. It speaks two dialects: OpenAI Chat Completions and the Anthropic Messages format, so existing SDKs and tools work by swapping the base URL. ## The API in one screenful | | | | --- | --- | | Base URL | `https://api.ambient.xyz` (OpenAI-style paths under `/v1`) | | Auth | `Authorization: Bearer `; keys from [app.ambient.xyz/keys](https://app.ambient.xyz/keys) | | OpenAI-compatible | `POST /v1/chat/completions` | | Anthropic-compatible | `POST /v1/messages` (+ `POST /v1/messages/count_tokens`) | | Model catalog | `GET /v1/models` (no auth required) | | Interactive spec | [api.ambient.xyz/docs](https://api.ambient.xyz/docs) (Swagger) · [api.ambient.xyz/redoc](https://api.ambient.xyz/redoc) | There is no Ambient-specific SDK to install. Use the official OpenAI or Anthropic SDK for your language and point it at Ambient; the [OpenAI SDK](https://ambient.xyz/docs/build/openai-sdk) and [Anthropic SDK](https://ambient.xyz/docs/build/anthropic-sdk) guides show how. > [!NOTE] > Because `GET /v1/models` needs no key, listing models does not validate a > key. The only way to prove a key works is a real completion; the > [quickstart](https://ambient.xyz/docs/get-started/quickstart) makes one in a few lines. ## In this section **Core API guides** - [Models and readiness](https://ambient.xyz/docs/build/models): the live catalog, what `is_ready` actually means, the `ambient/large` alias, and where pricing comes from - [Streaming](https://ambient.xyz/docs/build/streaming): SSE mechanics, the dual `reasoning`/`reasoning_content` delta keys, and stall handling - [Errors and retries](https://ambient.xyz/docs/build/errors): status-code taxonomy, including the `429 "No workers available"` vs rate-limit distinction - [Verified inference](https://ambient.xyz/docs/build/verified-inference): requesting verified inference and reading the verification fields in the response - [OpenAI SDK](https://ambient.xyz/docs/build/openai-sdk): Python and TypeScript setup and streaming - [Anthropic SDK](https://ambient.xyz/docs/build/anthropic-sdk): Messages-format setup, thinking blocks, and streaming **API reference** - [API reference](https://ambient.xyz/docs/build/api): every endpoint in the live OpenAPI spec, with field-by-field pages for [Chat Completions](https://ambient.xyz/docs/build/api/chat-completions) and the [Models endpoint](https://ambient.xyz/docs/build/api/models-endpoint) **Integrations** - [Claude Code](https://ambient.xyz/docs/build/claude-code): pointing Claude Code at the Anthropic-compatible API (base URL, key, and model) - [OpenCode](https://ambient.xyz/docs/build/opencode): selecting Ambient from the built-in provider menu - [OpenClaw](https://ambient.xyz/docs/build/openclaw): installing the Ambient plugin from ClawHub **On-chain** - [Pay per request with x402](https://ambient.xyz/docs/build/x402): pay-per-request inference through JumpGate. Quote, pay in USDC on Solana or Base, then stream the response - [Solana quickstart](https://ambient.xyz/docs/build/solana-quickstart): the Solana-compatible RPC endpoint and where the JumpGate relayer fits - [The auction program](https://ambient.xyz/docs/build/on-chain): JobRequest lifecycle, the second-lowest reverse auction, and requesting verified inference via CPI - [Tool Oracle](https://ambient.xyz/docs/build/tool-oracle): on-chain inference calls from Solana programs, with results written back on-chain New to Ambient entirely? Start with the [quickstart](https://ambient.xyz/docs/get-started/quickstart): key, first request, and what comes back. --- # Coding agents > Bring Ambient's verified open models into the coding agent you already use, whether Claude Code, Codex, OpenCode, or OpenClaw. Keep your agent as the orchestrator and route the token-heavy work to the network, or run the whole session on Ambient. - Canonical: https://ambient.xyz/docs/build/coding-agents --- Keep the coding agent you already use, and point it at Ambient for inference. You decide how much to hand over: keep your agent as the orchestrator and route only the token-heavy building to open models, or run the entire session on the network. One API key, verified inference, and you pick the model per task. [Diagram: A three-column diagram. On the left, four coding agents (Claude Code, Codex, OpenCode, and OpenClaw) each connect to a central Ambient node. The Ambient node is labelled one API key, verified inference, and you pick the model. From Ambient, three arrows fan out to the open models the network serves: GLM 5.2, plus Qwen3.6 27B and Qwen3.8 27B in preview, and more live on the network. The figure shows that whichever agent you use, it routes through a single Ambient integration to reach verified open models.] *Every integration lands on the same surface: your agent talks to Ambient with one key, and Ambient serves the open models. You choose which one, and every response carries a verified-inference receipt.* ## Pick your integration Each agent connects a little differently. Start here, then follow the guide for your tool. | Agent | How it connects | Reach for it when | | --- | --- | --- | | [Claude Code](https://ambient.xyz/docs/build/claude-code) | The `ambient-code` plugin (Claude orchestrates, routes the bulk to Ambient), or point Claude Code's model at Ambient for the whole session | You want a frontier model's judgment at open-model rates on the volume, or the whole session on Ambient | | [Codex](https://ambient.xyz/docs/build/codex) | The `ambient-codex` plugin, reached with `$ambient`; Delegate or Ambient-session (takeover) mode routes the bulk to Ambient | You work in Codex and want audits, builds, and large-repo work routed to Ambient while Codex orchestrates | | [OpenCode](https://ambient.xyz/docs/build/opencode) | Select Ambient from OpenCode's built-in provider menu | Ambient is a first-class provider option already in your tool | | [OpenClaw](https://ambient.xyz/docs/build/openclaw) | Install the Ambient plugin from ClawHub | You run OpenClaw and want Ambient as its inference provider | ## Two ways to work Across every integration, the same two working styles apply. Pick per project, or switch mid-session. ### Orchestrate + route Your agent stays the designer and reviewer. When there is a lot of code to write, it hands the token-heavy generation to an open model on Ambient, then reads every file back before anything is integrated. A frontier model's judgment on each line, open-model rates for the volume. Reach for this when the work is high-volume but well-specified (scaffolding, CRUD, test suites, mechanical refactors) and you want to spend premium tokens on the design and the review, not the typing. ### Full session on Ambient Run the whole coding session on open models. Point your agent's own inference at Ambient, or open a standalone agentic terminal on the network. Reach for this when cost is the priority, the task is routine, or you want the whole job done on open, verifiable models rather than a closed API. ## A second opinion on every commit Whichever agent builds, have a *different* model on Ambient review the diff. Independent readers catch what the author misses, at a price where running it on every commit is affordable. Both the Claude Code and Codex plugins ship an audit command for exactly this. ## What every integration shares - **One key.** Create it once at [app.ambient.xyz/keys](https://app.ambient.xyz/keys); it works across every agent. - **Your model choice.** The [model catalog](https://ambient.xyz/docs/build/models) shows what the network is serving right now. - **Verified inference.** Every response carries a receipt. See [Verified inference](https://ambient.xyz/docs/learn/proof-of-logits) for what it proves. - **Zero data retention by default.** You decide, per task, what leaves your machine and where it goes. ## Related - [Ambient Desktop](https://ambient.xyz/docs/use/desktop): a full desktop workspace that drives these agents with persistent plans and reviewable evidence - [Ambient Desktop vs Hermes](https://ambient.xyz/docs/use/desktop/comparisons/hermes): where the always-on, messaging-reachable agent fits - [Quickstart](https://ambient.xyz/docs/get-started/quickstart): keys, first request, and what comes back --- # Claude Code > Use Ambient from Claude Code. Install the ambient-code plugin so Claude routes the token-heavy building to Ambient's open models while it orchestrates, or point Claude Code's own model at Ambient to run the whole session on the network. - Canonical: https://ambient.xyz/docs/build/claude-code --- The [ambient-code](https://github.com/AmbientCrypto/ambient-code) plugin brings Ambient into a Claude Code session, reached with `/ambient`. Claude stays in charge: it plans, reviews, runs the tests, and commits on its frontier model, and routes the token-heavy work to Ambient's open models. You can also skip the plugin and point Claude Code's own provider at Ambient to run the whole session on the network. > [!NOTE] Status: beta > `ambient-code` is an early-access, open-source (MIT) plugin. Report bugs on > [GitHub](https://github.com/AmbientCrypto/ambient-code/issues). ## Install ### 1. Add the marketplace and install ```bash /plugin marketplace add AmbientCrypto/ambient-code /plugin install ambient-code@ambient ``` ### 2. Connect your key ```bash /ambient ``` Claude walks you through setup. You enter the key in your own terminal with hidden input, so it never passes through the chat, and the first run verifies it with a real call. ## Ways to work The plugin adds two session modes; a third path skips the plugin entirely and points Claude Code's own provider at Ambient. Pick per task. ### On demand (default) Claude Code works exactly as it does now. Ambient runs only when you ask for it by name, for a one-off audit, build, or second opinion. ### Delegate Turn on delegate mode with `/ambient on`. Claude plans and reviews on its frontier model and routes the token-heavy work to Ambient: larger audits, bulk reading, code drafts, and multi-file builds go to open models, while Claude keeps trivial edits and anything sensitive, destructive, or production-facing local. You get frontier orchestration at open-model rates on the volume. ```bash /ambient on ``` ### Run the whole session on Ambient Point Claude Code's provider at Ambient with environment variables, so every request runs on the network with no frontier model in the loop. Ambient speaks the Anthropic Messages format, so this is environment variables only. ```bash export ANTHROPIC_BASE_URL=https://api.ambient.xyz export ANTHROPIC_AUTH_TOKEN=your-ambient-api-key ``` Add them to `~/.zshrc` or `~/.bashrc` to make them permanent, then run `claude`. That is enough: Claude Code asks for Anthropic's `claude-*` model ids, and Ambient runs those on `ambient/large`, the alias that tracks the current production model. To pin a specific model instead, set the model variables to an exact id from [Models](https://ambient.xyz/docs/build/models); `ANTHROPIC_DEFAULT_HAIKU_MODEL` covers the background requests Claude Code makes for titles and summaries. ```bash export ANTHROPIC_MODEL=ambient/large-nonthinking export ANTHROPIC_DEFAULT_HAIKU_MODEL=ambient/large-nonthinking ``` > [!NOTE] What to expect on this route > Responses report the Ambient model that answered (for example `z-ai/glm-5.2`), not the `claude-*` name that was requested. The Anthropic-compatible endpoint requires paid credits, like the OpenAI-compatible one: on the free tier requests return `402`. A model id Ambient does not serve returns `400 Unknown model` with the list of valid ids. Already signed in to an Anthropic subscription? After launch, run `/status` to confirm Claude Code is using the Ambient provider. If it is still on your Anthropic login, run `/logout` inside Claude and relaunch. ## Workflows The same set of jobs the Codex plugin exposes, driven in plain language or by the command directly. Two sticky model lanes back them: chat/audit (`ask`, `audit`, `chat`, `map`) and code (`code`, `build`, `agent`). | Workflow | What it does | | --- | --- | | **Ask** | A one-shot answer or piped digest (`cat doc.txt \| ambient ask "..." -`), with optional `--consensus` across models | | **Audit** | An adversarial code review of a diff, files, or the whole repo (`--repo`), with multi-model consensus and an installable pre-commit gate (`--install-hook`) | | **Code** | A single-file code draft from the context you point it at | | **Build** | A multi-file build with a manifest-first plan and truncation-safe, reviewable writes (`--apply` writes) | | **Map** | One prompt run independently over many files, or one item per stdin line | | **Agent** | An interactive agentic terminal running on Ambient | | **Chat** | An interactive REPL with a per-turn token receipt | Generated code is untrusted until Claude reviews and tests it. Large builds are truncation-safe: complete files are kept, and anything cut off is re-requested on the next pass. ```bash git diff | ambient audit # second opinion on the diff ambient audit --repo . --install-hook # audit the repo, add a pre-commit gate ambient build "FastAPI /users CRUD plus pytest" --dir src/ --apply cat contract.txt | ambient ask "Summarize the obligations and risks." - ``` ## Choose your models Each lane keeps its own default, starting at `ambient/large`. `ambient models` shows what is serving now, `ambient use ` sets your default (`--chat` / `--code` scopes a single lane), and `ambient curate` chooses which models the menus surface. The [model catalog](https://ambient.xyz/docs/build/models) shows the live roster. ## Diagnostics ```bash ambient doctor # pinpoint a key, funds, model-availability, or network problem ambient usage # per-model calls and tokens (--days N) ambient mode off # turn delegate mode back off ``` ## What you get - **One key.** Create it once at [app.ambient.xyz/keys](https://app.ambient.xyz/keys). - **Your model choice.** The [model catalog](https://ambient.xyz/docs/build/models) shows what the network serves now. - **Verified inference.** Every response carries a receipt. See [Verified inference](https://ambient.xyz/docs/learn/proof-of-logits) for what it proves. - **Zero data retention by default.** You decide, per task, what leaves your machine. ## Related - [Coding agents](https://ambient.xyz/docs/build/coding-agents): every way to bring Ambient into your agent - [Codex](https://ambient.xyz/docs/build/codex): the same integration for Codex - [Models and readiness](https://ambient.xyz/docs/build/models): what the network is serving now - [ambient-code on GitHub](https://github.com/AmbientCrypto/ambient-code): source, issues, and the full command reference --- # Codex > Bring Ambient into Codex with the ambient-codex plugin. Route the bulk of your coding to Ambient's open models with Delegate and Ambient-session (takeover) modes, while Codex stays the control plane for review, tests, and the final commit. - Canonical: https://ambient.xyz/docs/build/codex --- The [ambient-codex](https://github.com/AmbientCrypto/ambient-codex) plugin brings Ambient into a Codex session, reached with `$ambient`. It adds chat, second-opinion audits, focused code drafts, multi-file builds, and repository maps. Codex stays the control plane; Ambient is the generation plane you route work to. > [!NOTE] Status: beta > `ambient-codex` is an early-access, open-source (MIT) plugin. Report bugs on > [GitHub](https://github.com/AmbientCrypto/ambient-codex/issues). ## Install ### 1. Install the plugin ```bash codex plugin marketplace add AmbientCrypto/ambient-codex codex plugin add ambient-codex@ambient-codex ``` Reinstalling uses the same second command. Start a new Codex thread after every install or update so Codex loads the current version. ### 2. Connect your Ambient API key (one time) The plugin lives in a versioned Codex cache, so it ships a small `ambient-codex` command that you use to store your key and run diagnostics. Create that command once, then run setup: ```bash PLUGIN_DIR="$(codex mcp get ambient --json | python3 -c 'import json,sys; print(json.load(sys.stdin)["transport"]["cwd"].rstrip("/."))')" "$PLUGIN_DIR/bin/ambient" link ambient-codex setup ``` `setup` hides the key while you type, verifies it with a real call, and stores it in your OS keychain. Never paste an API key into Codex chat. (If `~/.local/bin` is not on your `PATH`, the `link` command prints the exact line to add.) ### 3. Start Open a new Codex thread and enter `$ambient` for the control panel, or just ask for Ambient by name. ```text $ambient ``` > [!NOTE] Its own credential, on purpose > Ambient Codex uses its own `ambient-codex` keychain item and > `~/.config/ambient-codex` directory, and ignores the shared `AMBIENT_API_KEY` > variable so another Ambient install cannot supply this plugin's key. Set > `AMBIENT_CODEX_API_KEY` to override it deliberately. ## Ways to work Switch modes from `$ambient` (change mode). Modes are session-only; a fresh Codex thread starts in Normal Codex. ### On demand (Normal Codex) Codex works exactly as it does now. Ambient runs only when you ask for it by name, for a one-off audit, build, or second opinion. ### Delegate Codex plans and reviews, and routes the token-heavy work to Ambient. Larger audits, bulk reading, code drafts, and multi-file builds go to open models, while Codex keeps trivial edits and anything sensitive, destructive, or production-facing local. You get frontier orchestration at open-model rates on the volume. ### Takeover (Ambient session) Ambient becomes the direct chat and work engine for the thread, so the **bulk of the coding runs on Ambient's open models** and costs a fraction of a frontier session. **Codex stays the control plane** and acts as the orchestrator: it frames the acceptance contract, reviews every result, runs the tests, does the final commit, push, and merge, and keeps key handling, outbound-secret checks, destructive actions, and security-critical boundaries local. Ambient does the primary generation; Codex integrates it and uses its own tools around the result. Turn it on from `$ambient` (change mode, then Ambient session). ## Workflows Each workflow picks the right model and context budget for the job. Drive them in plain language, or open `$ambient` and choose one. | Workflow | What it does | | --- | --- | | **Ask** | A direct question or short chat with Ambient (`ask Ambient `) | | **Audit** | A second-opinion review of a diff, files, or the whole repo, with optional multi-model consensus (`audit this diff`, `audit this repo`) | | **Code** | A focused code draft from the context files you point it at | | **Build** | A multi-file build with a resumable manifest and bounded, reviewable writes (`build `) | | **Map** | Parallel summaries or classifications across many files | | **Agent** | A working-tree agent that inspects a scoped directory | Generated code is untrusted until you review and test it. On large work, Ambient reports partial or unread coverage instead of presenting a truncated result as complete. ## Choose your models Chat/review and code/build each keep their own default model. From `$ambient`: `set one model for all work`, `change chat/review model`, `change code/build model`, or `browse available models`. The [model catalog](https://ambient.xyz/docs/build/models) shows what the network is serving now. ## Diagnostics and removal ```bash ambient-codex doctor # check the install, key, and MCP server ambient-codex setup --remove # remove the stored key ambient-codex link --remove # remove the command codex plugin remove ambient-codex@ambient-codex ``` ## Run Codex directly on Ambient The plugin keeps Codex as the control plane and routes work to Ambient on demand. To point Codex's own provider at Ambient instead, add Ambient as a model provider in `~/.codex/config.toml`. Ambient serves the Responses wire format, so set `wire_api = "responses"`. ```toml model = "ambient/large" model_provider = "ambient" [model_providers.ambient] name = "Ambient" base_url = "https://api.ambient.xyz/v1" env_key = "AMBIENT_API_KEY" wire_api = "responses" ``` Export your key, then start Codex: ```bash export AMBIENT_API_KEY=your-ambient-api-key codex ``` > [!WARNING] Direct routing is partial today > Ambient's Responses endpoint works for simple string input and SSE > streaming, but full Codex CLI routing is still being finished: Codex sends > typed `input_text` content and namespace-style tool definitions that Ambient > does not fully accept yet. Use the plugin above for day-to-day work, and the > direct provider to evaluate raw requests. Only `wire_api = "responses"` is > supported; `"chat"` is rejected. ## What you get - **One key.** Create it once at [app.ambient.xyz/keys](https://app.ambient.xyz/keys). - **Your model choice.** The [model catalog](https://ambient.xyz/docs/build/models) shows what the network serves now. - **Verified inference.** Every response carries a receipt. See [Verified inference](https://ambient.xyz/docs/learn/proof-of-logits) for what it proves. - **Zero data retention by default.** You decide, per task, what leaves your machine. ## Related - [Coding agents](https://ambient.xyz/docs/build/coding-agents): every way to bring Ambient into your agent - [Claude Code](https://ambient.xyz/docs/build/claude-code): the same idea for Claude Code - [Models and readiness](https://ambient.xyz/docs/build/models): what the network is serving now - [ambient-codex on GitHub](https://github.com/AmbientCrypto/ambient-codex): source, issues, and the full command reference --- # OpenCode > Configure OpenCode to use Ambient as its inference provider by selecting Ambient from the built-in provider menu and pasting your API key. - Canonical: https://ambient.xyz/docs/build/opencode --- This guide shows how to configure [OpenCode](https://opencode.ai/) to use Ambient's inference API. ## Prerequisites 1. An [Ambient account](https://app.ambient.xyz) with credits 2. An Ambient API key from [app.ambient.xyz/keys](https://app.ambient.xyz/keys) 3. OpenCode installed ## Configuration ### 1. Launch OpenCode ```bash opencode ``` ### 2. Open the model selection menu Type `/models` to launch the inference model selection menu. ### 3. Open the provider selection menu Hit `Ctrl-A` to open the provider selection menu. ### 4. Select Ambient Type `Ambient` in the search box and press Enter. ### 5. Paste your API key You'll be prompted for your Ambient API key. Paste the key from [app.ambient.xyz/keys](https://app.ambient.xyz/keys) when asked. ### 6. Pick a model Then, select your desired model and proceed to complete the setup. ## Resources - [Quickstart](https://ambient.xyz/docs/get-started/quickstart): keys, first request, and what comes back - [Models and readiness](https://ambient.xyz/docs/build/models): what the network is serving right now - [OpenCode documentation](https://opencode.ai/) (external) --- # OpenClaw > Configure OpenClaw to use Ambient as its inference provider by installing the Ambient plugin from ClawHub and onboarding with your API key. - Canonical: https://ambient.xyz/docs/build/openclaw --- OpenClaw can use Ambient's inference API as its provider through the Ambient plugin. Configuration is one plugin install plus onboarding with your API key. ## Prerequisites 1. An [Ambient account](https://app.ambient.xyz) with credits 2. An Ambient API key from [app.ambient.xyz/keys](https://app.ambient.xyz/keys) 3. OpenClaw installed ## Configuration Install the Ambient plugin from ClawHub: ```bash openclaw plugins install clawhub:@ambientcrypto/openclaw ``` Then run onboarding with Ambient as the selected inference provider: ```bash openclaw onboard --auth-choice ambient-api-key ``` You'll be prompted for your Ambient API key. Paste the key from [app.ambient.xyz/keys](https://app.ambient.xyz/keys) when asked. ## Usage Once configured, run OpenClaw as normal: ```bash openclaw ``` OpenClaw automatically routes requests through Ambient's inference API. ## Resources - [Quickstart](https://ambient.xyz/docs/get-started/quickstart): keys, first request, and what comes back - [Models and readiness](https://ambient.xyz/docs/build/models): what the network is serving right now - [OpenClaw documentation](https://openclaw.ai/) (external) --- # OpenAI SDK > Use the official OpenAI SDK with Ambient. Point base_url at api.ambient.xyz/v1, then chat and stream exactly as you would against OpenAI. - Canonical: https://ambient.xyz/docs/build/openai-sdk --- The official OpenAI SDK works with Ambient as-is. The only changes from a stock OpenAI setup are the base URL and the key. ## Prerequisites 1. An Ambient API key from [app.ambient.xyz/keys](https://app.ambient.xyz/keys) 2. The OpenAI SDK installed for your language ## Python Install: ```bash pip install openai ``` ### Usage ```python title="ambient_openai.py" from openai import OpenAI client = OpenAI( base_url="https://api.ambient.xyz/v1", api_key="your-ambient-api-key", ) response = client.chat.completions.create( model="ambient/large", messages=[ {"role": "user", "content": "Hello, how are you?"} ], ) message = response.choices[0].message if message.reasoning_content: print("Reasoning:", message.reasoning_content) print("Response:", message.content) ``` ### Streaming ```python title="ambient_openai_stream.py" from openai import OpenAI client = OpenAI( base_url="https://api.ambient.xyz/v1", api_key="your-ambient-api-key", ) stream = client.chat.completions.create( model="ambient/large", messages=[ {"role": "user", "content": "Write a short poem about coding."} ], stream=True, ) for chunk in stream: delta = chunk.choices[0].delta if delta.reasoning_content: print(delta.reasoning_content, end="", flush=True) if delta.content: print(delta.content, end="", flush=True) ``` ## JavaScript / TypeScript Install: ```bash npm install openai ``` ### Usage ```javascript title="ambient-openai.js" import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.ambient.xyz/v1", apiKey: "your-ambient-api-key", }); const response = await client.chat.completions.create({ model: "ambient/large", messages: [ { role: "user", content: "Hello, how are you?" } ], }); const message = response.choices[0].message; if (message.reasoning_content) { console.log("Reasoning:", message.reasoning_content); } console.log("Response:", message.content); ``` ### Streaming ```javascript title="ambient-openai-stream.js" import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.ambient.xyz/v1", apiKey: "your-ambient-api-key", }); const stream = await client.chat.completions.create({ model: "ambient/large", messages: [ { role: "user", content: "Write a short poem about coding." } ], stream: true, }); for await (const chunk of stream) { const delta = chunk.choices[0]?.delta; if (delta?.reasoning_content) { process.stdout.write(delta.reasoning_content); } if (delta?.content) { process.stdout.write(delta.content); } } ``` [Streaming](https://ambient.xyz/docs/build/streaming) covers the full behavior: non-streamed fallback responses, multi-line SSE events, and stall detection. ## Environment variables You can also configure the SDK through environment variables: ```bash export OPENAI_BASE_URL=https://api.ambient.xyz/v1 export OPENAI_API_KEY=your-ambient-api-key ``` Then instantiate the client without arguments: ```python # Python client = OpenAI() ``` ```javascript // JavaScript const client = new OpenAI(); ``` ## Resources - [Ambient API reference](https://api.ambient.xyz/redoc) - [Get API keys](https://app.ambient.xyz/keys) - [Models and readiness](https://ambient.xyz/docs/build/models) - [OpenAI SDK documentation](https://platform.openai.com/docs/libraries) --- # Anthropic SDK > Use the official Anthropic SDK with Ambient. Point base_url at api.ambient.xyz and use the Messages API, including thinking blocks and streaming. - Canonical: https://ambient.xyz/docs/build/anthropic-sdk --- Ambient implements the Anthropic Messages format at `POST /v1/messages` (plus `POST /v1/messages/count_tokens`), so the official Anthropic SDK works by swapping the base URL. ## Prerequisites 1. An Ambient API key from [app.ambient.xyz/keys](https://app.ambient.xyz/keys) 2. The Anthropic SDK installed for your language ## Python Install: ```bash pip install anthropic ``` ### Usage ```python title="ambient_anthropic.py" import anthropic client = anthropic.Anthropic( base_url="https://api.ambient.xyz", api_key="your-ambient-api-key", ) message = client.messages.create( model="ambient/large", max_tokens=1024, messages=[ {"role": "user", "content": "Hello, how are you?"} ], ) for block in message.content: if block.type == "thinking": print("Reasoning:", block.thinking) elif block.type == "text": print("Response:", block.text) ``` In the Messages format, a model's reasoning arrives as `thinking` content blocks alongside the `text` blocks, so there is only one place to look for it. ### Streaming ```python title="ambient_anthropic_stream.py" import anthropic client = anthropic.Anthropic( base_url="https://api.ambient.xyz", api_key="your-ambient-api-key", ) with client.messages.stream( model="ambient/large", max_tokens=1024, messages=[ {"role": "user", "content": "Write a short poem about coding."} ], ) as stream: for event in stream: if event.type == "content_block_delta": if event.delta.type == "thinking_delta": print(event.delta.thinking, end="", flush=True) elif event.delta.type == "text_delta": print(event.delta.text, end="", flush=True) ``` ## JavaScript / TypeScript Install: ```bash npm install @anthropic-ai/sdk ``` ### Usage ```javascript title="ambient-anthropic.js" import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic({ baseURL: "https://api.ambient.xyz", apiKey: "your-ambient-api-key", }); const message = await client.messages.create({ model: "ambient/large", max_tokens: 1024, messages: [ { role: "user", content: "Hello, how are you?" } ], }); for (const block of message.content) { if (block.type === "thinking") { console.log("Reasoning:", block.thinking); } else if (block.type === "text") { console.log("Response:", block.text); } } ``` ### Streaming ```javascript title="ambient-anthropic-stream.js" import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic({ baseURL: "https://api.ambient.xyz", apiKey: "your-ambient-api-key", }); const stream = client.messages.stream({ model: "ambient/large", max_tokens: 1024, messages: [ { role: "user", content: "Write a short poem about coding." } ], }); for await (const event of stream) { if (event.type === "content_block_delta") { if (event.delta.type === "thinking_delta") { process.stdout.write(event.delta.thinking); } else if (event.delta.type === "text_delta") { process.stdout.write(event.delta.text); } } } ``` ## Environment variables You can also configure the SDK through environment variables: ```bash export ANTHROPIC_BASE_URL=https://api.ambient.xyz export ANTHROPIC_API_KEY=your-ambient-api-key ``` Then instantiate the client without arguments: ```python # Python client = anthropic.Anthropic() ``` ```javascript // JavaScript const client = new Anthropic(); ``` ## Resources - [Ambient API reference](https://api.ambient.xyz/redoc) - [Get API keys](https://app.ambient.xyz/keys) - [Models and readiness](https://ambient.xyz/docs/build/models) - [Anthropic SDK documentation](https://docs.anthropic.com/en/api/client-sdks) --- # Models and readiness > The Ambient model catalog. What the is_ready flag does and doesn't mean, what the ambient/large alias is, and why pricing always comes from the API. - Canonical: https://ambient.xyz/docs/build/models --- Ambient serves a catalog of open models, published live at `GET /v1/models`. Anything listed there is served. GLM 5.2 (`z-ai/glm-5.2`, also reachable as `ambient/large`) is the supported production model; other listed models may be previews that are served and usable but come with no guarantees. ## The catalog | Model | ID | Context | Input / M | Output / M | | --- | --- | --- | --- | --- | | GLM 5.2 (alias) | `ambient/large` | 202K | $0.60 | $2.00 | | Qwen3.6 27B | `qwen/qwen3.6-27b` | 32K | $0.32 | $3.20 | | Qwen3.8 27B | `qwen/qwen3.8-27b` | 32K | $0.32 | $3.20 | | GLM 5.2 | `z-ai/glm-5.2` | 202K | $0.60 | $2.00 | Catalog as of the 2026-09-09 snapshot; the live list is `GET /v1/models`. The same data is available live, with no API key: ```bash curl https://api.ambient.xyz/v1/models ``` Each entry carries the model id, context length, max output length, per-million-token pricing (`pricing.input` / `pricing.output`), `supported_features` (such as `tools`, `json_mode`, `structured_outputs`, `reasoning`, `logprobs`), quantization, and an `is_ready` flag (explained below). ## What `is_ready` means `is_ready` is a routing flag consumed by OpenRouter: it toggles whether OpenRouter sends traffic to that model. It is not a served/not-served signal. A model can be listed, served, and answering requests with `is_ready: false`, so don't gate model selection on it. If a model is in the catalog, you can request it. - Capacity is reported per request, not in the catalog. When a model has no capacity at the moment, the request returns `429` with a message like `"No workers available"` or `"Upstream request failed"`. That is **not** a rate limit, and authentication is unaffected: retry with short, jittered backoff, or fail over to another listed model. If the same model keeps failing for minutes, treat it as down. See [Errors and retries](https://ambient.xyz/docs/build/errors). - Pin GLM 5.2 (`z-ai/glm-5.2` or `ambient/large`) for production. Other listed models may be previews: served and usable, but with no guarantees, and they may later be limited to specific partners. Keep a fallback in mind if you build on one. - Miners load-balance, so fanning out many parallel requests to one model works. ```ts title="list-models.ts" const res = await fetch("https://api.ambient.xyz/v1/models"); const { data } = await res.json(); // Everything listed is served. is_ready is an OpenRouter routing flag, // not an availability signal, so there is nothing to filter on here. console.log(data.map((m: { id: string }) => m.id)); ``` ## The `ambient/large` alias `ambient/large` is an Ambient-managed alias rather than a distinct model: its listed specs and pricing mirror whichever concrete catalog model it currently resolves to, so read them from its own live catalog entry instead of assuming a fixed target. Use it when you want Ambient's default large model without pinning a specific id; pin a concrete id when you need reproducibility. ## Pricing comes from the API Per-model prices are published in the catalog itself as USD per million tokens (`pricing.input` and `pricing.output`), so the table above stays in sync with `GET /v1/models`. The API itself does not expose a balance or spend endpoint. Track credits and usage in the Ambient app (Billing and Usage), or meter your own usage locally and price it against the catalog. Token counts are in the `usage` object of each completion response (for streamed responses, set `stream_options: {"include_usage": true}` to receive usage in the final chunk). --- # Streaming > Stream completions over SSE. Standard OpenAI-style chunks, the dual reasoning/reasoning_content delta keys, and how to detect stalls and truncation. - Canonical: https://ambient.xyz/docs/build/streaming --- Set `"stream": true` on `POST /v1/chat/completions` to receive the response as server-sent events. The chunks are standard OpenAI `chat.completion.chunk` objects, with a few network realities worth handling deliberately. ## Basic streaming ### curl ```bash curl https://api.ambient.xyz/v1/chat/completions \ -H "Authorization: Bearer $AMBIENT_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: text/event-stream" \ -d '{ "model": "ambient/large", "messages": [ {"role": "user", "content": "Write a short poem about verification."} ], "max_tokens": 512, "stream": true, "stream_options": {"include_usage": true} }' ``` Give `max_tokens` headroom. It caps reasoning and answer combined, and reasoning models can spend a small budget entirely on thinking deltas. ### Python ```python title="stream.py" from openai import OpenAI client = OpenAI( base_url="https://api.ambient.xyz/v1", api_key="your-ambient-api-key", ) stream = client.chat.completions.create( model="ambient/large", messages=[ {"role": "user", "content": "Write a short poem about verification."} ], # max_tokens caps reasoning + answer combined; reasoning models can # spend a small budget entirely on thinking deltas. max_tokens=512, stream=True, stream_options={"include_usage": True}, ) for chunk in stream: delta = chunk.choices[0].delta if chunk.choices else None if delta is None: continue # Different models stream reasoning under different keys, so read # both to avoid missing whichever one this model uses. reasoning = getattr(delta, "reasoning", None) or getattr( delta, "reasoning_content", None ) if reasoning: print(reasoning, end="", flush=True) if delta.content: print(delta.content, end="", flush=True) ``` ### TypeScript ```ts title="stream.ts" import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.ambient.xyz/v1", apiKey: process.env.AMBIENT_API_KEY, }); const stream = await client.chat.completions.create({ model: "ambient/large", messages: [ { role: "user", content: "Write a short poem about verification." }, ], // max_tokens caps reasoning + answer combined; reasoning models can // spend a small budget entirely on thinking deltas. max_tokens: 512, stream: true, stream_options: { include_usage: true }, }); for await (const chunk of stream) { const delta = chunk.choices[0]?.delta as | { content?: string; reasoning?: string; reasoning_content?: string } | undefined; if (!delta) continue; // Different models stream reasoning under different keys, so read // both to avoid missing whichever one this model uses. const reasoning = delta.reasoning ?? delta.reasoning_content; if (reasoning) process.stdout.write(reasoning); if (delta.content) process.stdout.write(delta.content); } ``` ## Dual reasoning delta keys Different models on the network emit their thinking trace under different delta keys: some stream it as `reasoning_content` (OpenAI-style), others as `reasoning`. **Read both keys.** A client that only watches one of them will silently drop the entire reasoning channel for models that use the other. With a reasoning model, that dropped channel can be most of the tokens you paid for. ## Realities to handle - **The endpoint may answer non-streamed anyway.** Occasionally a request with `stream: true` comes back as a single JSON body instead of SSE. Check the response `Content-Type`: if it is not `text/event-stream`, parse the body as a regular completion rather than failing. - **SSE `data:` fields can span multiple lines.** Accumulate all `data:` lines of an event before JSON-parsing, per the SSE spec. One-line-one-JSON parsers will break. - **A clean end is `[DONE]` or a `finish_reason`.** A stream that hits EOF without either is a truncation. Treat the partial output as salvageable data rather than a failure, and treat a dropped connection mid-stream the same way. - **Stalls and keep-alives.** A wedged worker can hold the socket open with empty deltas or keep-alives while producing no content. Run a no-progress timer (time since the last delta that actually carried text) alongside an overall deadline, and abandon the stream when it trips. Don't rely on the connection closing on its own. > [!TIP] > `stream_options: {"include_usage": true}` adds a final usage chunk with > token counts. That matters because there is no server-side usage endpoint > to reconcile against later. --- # Errors and retries > The Ambient API error taxonomy. What each status code actually means, why 429 "No workers available" is not a rate limit, and safe retry rules. - Canonical: https://ambient.xyz/docs/build/errors --- Every error from `api.ambient.xyz` maps to a specific cause and a specific reaction. ## Error taxonomy | Status | Signal in the body | What it means | What to do | | --- | --- | --- | --- | | `401` / `403` | `authentication_error` or similar | Key missing, invalid, or revoked | Re-check the key; create a new one at [app.ambient.xyz/keys](https://app.ambient.xyz/keys) | | `402` (or a `403` whose message mentions funds/quota) | "insufficient funds", "quota" | Account out of funds | Top up; check the funds wording before classifying a `403` as an auth failure | | `400` | "context", "context_length", "maximum context", "too long" | Input exceeds the model's context window | Trim the prompt, or pick a larger-context model from [`GET /v1/models`](https://ambient.xyz/docs/build/models) | | `400` | "Unknown model", `invalid_request_error` | The model id isn't in the catalog (or has been retired) | Use an exact id from `GET /v1/models` (for example `z-ai/glm-5.2`) | | `429` + `"No workers available"` or `"Upstream request failed"` | no-workers / upstream wording | Not a rate limit. The model has no capacity right now | Retry with short, jittered backoff, or fail over to another model listed on `GET /v1/models`; if it keeps failing for minutes, the model is down | | `429` (plain) | rate-limit wording | You are sending too fast | Back off with jitter and retry | | `5xx` | None | Ambient-side failure | Retry cautiously; see below | ## The two kinds of 429 The distinction matters because the right reactions differ. A `429` whose body says `"No workers available"` or `"Upstream request failed"` is a capacity signal: your auth and pacing are fine, but no worker picked up the request. Retry with short, jittered backoff, or fail over to another model listed on `GET /v1/models`. If the same model keeps failing for minutes, treat it as down. A plain `429` is classic rate limiting: slow down and retry the same request with exponential backoff. A capacity `429` looks like this: ```json {"error": {"message": "No workers available", "type": "upstream_error"}} ``` The `type` can be `upstream_error` or `rate_limit_exceeded` for the same condition, so key on the message wording, not the type. Ambient reports capacity as `429` rather than `503` for compatibility with upstream routers such as OpenRouter. A capacity `429` carries no `Retry-After` header, and you don't need one: the body tells you which case you are in, and short jittered backoff (or failover) is the right reaction to a capacity error regardless. Do not consult `is_ready` on `GET /v1/models` to decide what to do. It is an OpenRouter routing flag, not an availability signal, and everything the catalog lists is served; see [Models and readiness](https://ambient.xyz/docs/build/models). ## Retry guidance - **Retry `502`/`503`/`504` only for idempotent GETs** (such as `GET /v1/models`), and only once or twice. - **Do not blindly retry a timed-out completion POST.** A request that timed out on your side may still have been processed server-side, so a blind retry can charge you twice for the same generation. If you must retry, do it deliberately and log the `inference-id` response header of every attempt so you can reconcile. - **Treat mid-stream disconnects as truncation.** Keep the partial output; see [Streaming](https://ambient.xyz/docs/build/streaming) for stall and truncation detection. > [!WARNING] > The API does not expose a balance endpoint. Track credits and usage in > the Ambient app (the Usage and Billing pages), or meter locally using the `usage` > object each response returns and the per-model pricing in > `GET /v1/models`. --- # Verified inference > The verification surface of the Ambient API, covering request flags and the verified and merkle_root response fields. - Canonical: https://ambient.xyz/docs/build/verified-inference --- Verified inference is Ambient's core promise: proof that the requested model ran on the requested prompt and produced the returned output. The API surface for it is small: three request flags, two response fields, and one response header you can rely on today. > [!WARNING] Status: beta > The verification request flags are accepted by the live API, but the > spec-declared `verified` and `merkle_root` response fields are **not yet > populated on the live gateway**: responses currently omit both, with all > flag combinations, streaming and non-streaming. Build against the flags > now; do not build logic that depends on the fields being present until > they ship. ## Request flags `POST /v1/chat/completions` (and the legacy completions, runs, and responses endpoints) accepts these Ambient-specific fields alongside the standard OpenAI parameters. All default to `false`: | Flag | Spec description | | --- | --- | | `emit_verified` | "Whether to return verification status" | | `wait_for_verification` | "Whether to wait for verification to complete before completing the request" | | `emit_ambient_events` | "Whether to return lifecycle events" | All three flags are accepted in both streaming and non-streaming requests. ```bash curl https://api.ambient.xyz/v1/chat/completions \ -H "Authorization: Bearer $AMBIENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ambient/large", "messages": [{"role": "user", "content": "Say hello from Ambient."}], "max_tokens": 512, "emit_verified": true, "wait_for_verification": true }' ``` `max_tokens` caps reasoning and answer tokens combined, so on reasoning models set it high enough to leave room for the answer after any reasoning. ## Response fields The public OpenAPI spec ([api.ambient.xyz/openapi.json](https://api.ambient.xyz/openapi.json)) declares two verification fields on the chat-completion response: | Field | Type | What it is | | --- | --- | --- | | `verified` | `boolean \| null` | Per-response verification verdict | | `merkle_root` | string | Cryptographic commitment over the inference | Verification is delivered inline: a verdict plus a Merkle-root commitment on the response itself. No separate receipt API or verification-lookup endpoint exists in the public spec today. ## What you can rely on right now - Every inference returns an `inference-id` response header, a stable identifier for the request, also visible as `x-request-id` and embedded in the completion `id`. Log it for every request: it is the durable handle for the inference, and the natural key for any future verification lookup. - The flags are safe to send today: `emit_verified: true` has no latency cost, so clients can adopt it ahead of the fields shipping. - `wait_for_verification` and `emit_ambient_events` are accepted today and become active when inline verification ships. ## How verification works underneath The network's verification mechanism is Proof of Logits: logits are fingerprints of a model's execution, and a validator only needs to re-run a single token position to check an output that took thousands of tokens to produce. See [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits) for the concept-level explanation. --- # API reference > The full Ambient HTTP API surface, covering base URL, auth, compatibility dialects, and a generated table of every endpoint in the live OpenAPI spec. - Canonical: https://ambient.xyz/docs/build/api --- This is the reference index for the Ambient HTTP API: every endpoint the live OpenAPI spec exposes. The two endpoints most integrations touch, [Chat Completions](https://ambient.xyz/docs/build/api/chat-completions) and [Models](https://ambient.xyz/docs/build/api/models-endpoint), each have a field-by-field page. ## Basics | | | | --- | --- | | Base URL | `https://api.ambient.xyz` (OpenAI-style paths under `/v1`) | | Auth | `Authorization: Bearer `; keys from [app.ambient.xyz/keys](https://app.ambient.xyz/keys) | | No-auth exception | `GET /v1/models` works without a key | | Content type | `application/json` | | Spec | [openapi.json](https://api.ambient.xyz/openapi.json), "Ambient Public HTTP API" | ## Prerequisites Get an API key through [app.ambient.xyz/keys](https://app.ambient.xyz/keys), or create and fund an API-only account through [Headless x402 subscriptions](https://ambient.xyz/docs/build/x402-subscriptions) without using the Ambient UI. For speed and flexibility, we recommend using direct API calls. These allow you to control thinking tokens (balancing speed and latency) and perform Deep Research directly. The [streaming Python demo](https://drive.google.com/file/d/1E1UCWc2DPR4VFM9P0PEVfcPDNoqkKtCh/view?usp=drive_link) covers reasoning and non-reasoning modes; place your API key in a file named `ambient_api_key.txt` in the same directory. The [condensed API reference](https://drive.google.com/file/d/1GEkctbduqsPzuzl6GYJcCbLgkTAZTJyI/view?usp=sharing) contains Python examples of all functions. ## Integration options Point the official OpenAI SDK at Ambient's base URL. Ideal if you already use OpenAI's SDK or prefer its interface. Python and JavaScript examples. Point the official Anthropic SDK at Ambient and use the Messages API format. Python and JavaScript examples. Make HTTP requests directly, with no SDK. Full control, any language. The interactive API docs list every endpoint and schema and let you try requests in the browser. ## Compatibility The API speaks the two dominant dialects, so official SDKs work by swapping the base URL: - `POST /v1/chat/completions` accepts the standard OpenAI Chat Completions parameters (plus [Ambient extensions](https://ambient.xyz/docs/build/api/chat-completions#ambient-extension-fields)). Setup in the [OpenAI SDK guide](https://ambient.xyz/docs/build/openai-sdk). - `POST /v1/messages` and `POST /v1/messages/count_tokens` implement Anthropic Messages. Setup in the [Anthropic SDK guide](https://ambient.xyz/docs/build/anthropic-sdk). - `POST /v1/responses` (the OpenAI Responses API) works for simple string input, message arrays with string content, and SSE streaming. It does not accept typed `input_text` content parts or namespace-style tool definitions, so clients that require them (including the Codex CLI) cannot route through it. ## All endpoints **Anthropic** | Method | Path | Summary | | --- | --- | --- | | POST | `/v1/messages/count_tokens` | Count Tokens | | POST | `/v1/messages` | Messages | **Completions** | Method | Path | Summary | | --- | --- | --- | | POST | `/v1/chat/completions` | Chat Completions | | POST | `/v1/completions` | Completions | **Models** | Method | Path | Summary | | --- | --- | --- | | GET | `/v1/models` | List Models | | GET | `/v1/models/{model_id}` | Get Model | **Assistants** | Method | Path | Summary | | --- | --- | --- | | GET | `/v1/assistants` | List Assistants | | POST | `/v1/assistants` | Create Assistant | | GET | `/v1/assistants/{assistant_id}` | Get Assistant | | POST | `/v1/assistants/{assistant_id}` | Update Assistant | | DELETE | `/v1/assistants/{assistant_id}` | Delete Assistant | **Threads** | Method | Path | Summary | | --- | --- | --- | | GET | `/v1/threads` | List Threads | | POST | `/v1/threads` | Create Thread | | GET | `/v1/threads/{thread_id}` | Get Thread | | POST | `/v1/threads/{thread_id}` | Update Thread | | DELETE | `/v1/threads/{thread_id}` | Delete Thread | **Runs** | Method | Path | Summary | | --- | --- | --- | | GET | `/v1/threads/{thread_id}/runs` | List Runs | | POST | `/v1/threads/{thread_id}/runs` | Create Run | | GET | `/v1/threads/{thread_id}/runs/{run_id}` | Get Run | | POST | `/v1/threads/{thread_id}/runs/{run_id}` | Update Run | | DELETE | `/v1/threads/{thread_id}/runs/{run_id}` | Delete Run | | GET | `/v1/threads/{thread_id}/runs/{run_id}/steps` | Get Run Steps | | GET | `/v1/threads/{thread_id}/runs/{run_id}/steps/{step_id}` | Get Run Step | **Messages** | Method | Path | Summary | | --- | --- | --- | | GET | `/v1/threads/{thread_id}/messages` | List Messages | | POST | `/v1/threads/{thread_id}/messages` | Create Message | | GET | `/v1/threads/{thread_id}/messages/{message_id}` | Get Message | | POST | `/v1/threads/{thread_id}/messages/{message_id}` | Update Message | | DELETE | `/v1/threads/{thread_id}/messages/{message_id}` | Delete Message | **Responses** | Method | Path | Summary | | --- | --- | --- | | GET | `/v1/responses` | List Response | | POST | `/v1/responses` | Create Response | | GET | `/v1/responses/{response_id}` | Get Response | | DELETE | `/v1/responses/{response_id}` | Delete Response | | GET | `/v1/responses/{response_id}/thread` | Get Thread | | POST | `/v1/responses/{response_id}/cancel` | Cancel Response | **Research** | Method | Path | Summary | | --- | --- | --- | | GET | `/v1/research` | List Research | | POST | `/v1/research` | Conduct research on a topic | | POST | `/v1/research/generate-pdf` | Generate a research report PDF | | GET | `/v1/research/{research_id}` | Get research details | | DELETE | `/v1/research/{research_id}` | Delete a research record | | GET | `/v1/research/{research_id}/actions` | Stream research actions in real-time | **Tools** | Method | Path | Summary | | --- | --- | --- | | POST | `/v1/tools` | Execute tool calls directly | **Referrals** | Method | Path | Summary | | --- | --- | --- | | GET | `/referral/dashboard` | Get Referral Dashboard | 42 operations in Ambient Public HTTP API v0.1.0. Current as of 2026-07-04; the live spec is at https://api.ambient.xyz/openapi.json. Beyond chat completions and models, the spec also exposes an Assistants/Threads/Runs suite, the Responses API, a Research API, and direct tool execution. For those groups, the interactive spec below is the reference. ## Interactive spec of record The server publishes its own always-current, schema-exact reference: - [api.ambient.xyz/docs](https://api.ambient.xyz/docs): Swagger UI, where you can try requests in the browser - [api.ambient.xyz/redoc](https://api.ambient.xyz/redoc): ReDoc, for readable schema browsing --- # Chat Completions > POST /v1/chat/completions field by field. The OpenAI-compatible request schema, the Ambient extension flags, and the response shape. - Canonical: https://ambient.xyz/docs/build/api/chat-completions --- `POST /v1/chat/completions` is the core inference endpoint: OpenAI-format in, OpenAI-format out. The field-level reference is below; the [quickstart](https://ambient.xyz/docs/get-started/quickstart) covers your first call, and the [OpenAI SDK guide](https://ambient.xyz/docs/build/openai-sdk) covers client setup. ### POST /v1/chat/completions Chat Completions **Parameters** | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `iv` | header | string \| null | — | Initialization vector for encryption. Only supported with streaming right now. | | `public-key` | header | string \| null | — | Public key for encryption. Only supported with streaming right now. | **Request body — ChatCompletionsRequest** | Field | Type | Required | Description | | --- | --- | --- | --- | | `messages` | ChatCompletionsMessage[] | Yes | — | | `emit_ambient_events` | boolean | — | Whether to return lifecycle events | | `emit_usage` | boolean | — | Whether to return usage information | | `emit_verified` | boolean | — | Whether to return verification status | | `enabled_tools` | string[] \| null | — | List of enabled tools. Supported tools: ['`*`', 'websearch', 'retrieval', 'crypto_price', 'stock_price', 'weather', 'currency_convert', 'calculator']. Use [`*`] to enable all tools. | | `force_auction_v2` | boolean | — | Force routing via the NATS-based auction v2 request router, bypassing rollout sampling. | | `frequency_penalty` | number \| null | — | — | | `guided_json` | object \| string \| null | — | JSON schema for guided generation | | `include_reasoning` | boolean \| null | — | — | | `logit_bias` | object \| null | — | — | | `logprobs` | boolean \| null | — | — | | `max_completion_tokens` | integer \| null | — | Maximum number of tokens to generate | | `max_tokens` | integer \| null | — | Maximum number of tokens to generate | | `min_p` | number \| null | — | — | | `model` | string \| null | — | — | | `presence_penalty` | number \| null | — | — | | `reasoning` | ReasoningConfiguration \| null | — | Configuration for the model's reasoning capabilities. | | `repetition_penalty` | number \| null | — | — | | `response_format` | object \| string \| null | — | — | | `seed` | integer \| null | — | — | | `stop` | string \| string[] \| null | — | — | | `stream` | boolean | — | — | | `stream_options` | api__routes__types__StreamOptions \| null | — | — | | `temperature` | number \| null | — | Sampling temperature | | `thinking_budget` | integer \| null | — | WARNING. DEPRECATED. Use reasoning configuration instead. | | `tool_choice` | string \| object \| null | — | — | | `tools` | ChatCompletionToolsParam[] \| null | — | — | | `top_k` | integer \| null | — | — | | `top_logprobs` | integer \| null | — | — | | `top_p` | number \| null | — | — | | `wait_for_verification` | boolean \| null | — | Whether to wait for verification to complete before completing the request | **Response (200) — ChatCompletionResponse** | Field | Type | Required | Description | | --- | --- | --- | --- | | `choices` | Choice[] | Yes | — | | `created` | integer | Yes | — | | `id` | string | Yes | — | | `merkle_root` | string | Yes | — | | `model` | string | Yes | — | | `object` | "chat.completion" | Yes | — | | `service_tier` | "auto" \| "default" \| "flex" \| "scale" \| "priority" \| null | — | — | | `system_fingerprint` | string \| null | — | — | | `usage` | CompletionUsage \| null | — | — | | `verified` | boolean \| null | — | — | Current as of 2026-07-04; the live spec is at https://api.ambient.xyz/openapi.json. ## Request essentials Only `messages` is required by the schema, but in practice you always set: - `model`: any exact id listed by [`GET /v1/models`](https://ambient.xyz/docs/build/api/models-endpoint). Every listed model is served; `is_ready` is a routing flag, not a liveness signal, so do not gate on it. When a model is temporarily out of capacity the API returns `429` with a message such as `"No workers available"` or `"Upstream request failed"` (the `type` varies, so key on the message): retry with short jittered backoff or fail over to another listed model. See [Errors and retries](https://ambient.xyz/docs/build/errors). - `max_tokens`: give it real headroom. The examples here use `512`. The cap covers reasoning and answer combined, and most Ambient models are reasoning models: with a small budget the model can spend every token thinking and return `"content": null`. Always check `finish_reason`: `"length"` with `null` content means the budget went to reasoning. For short answers, turn thinking off instead of shrinking the budget; see [Short answers: turn thinking off](#short-answers-turn-thinking-off). ```bash title="minimal-request.sh" curl https://api.ambient.xyz/v1/chat/completions \ -H "Authorization: Bearer $AMBIENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ambient/large", "messages": [{"role": "user", "content": "Say hello from Ambient."}], "max_tokens": 512 }' ``` Sampling parameters (`temperature`, `top_p`, `top_k`, `min_p`, penalties, `seed`, `stop`, `logprobs`) follow OpenAI semantics; each model advertises what it supports in `supported_sampling_parameters` on `GET /v1/models`. Tool calling (`tools`, `tool_choice`), JSON mode (`response_format`), and guided generation (`guided_json`) work on models whose `supported_features` list them. ## Ambient extension fields Alongside the standard parameters, the request schema accepts Ambient-specific fields. The three verification flags all default to `false`: | Field | What it does | Status | | --- | --- | --- | | `emit_verified` | Requests verification status in the response. | Accepted now; the `verified` field returns results when verified inference ships. | | `wait_for_verification` | Blocks the response until verification completes. | Accepted now; takes effect when verified inference ships. | | `emit_ambient_events` | Requests lifecycle events for the inference. | Accepted now; events ship with verified inference. | You can set these flags today, in both streaming and non-streaming requests; they are forward-compatible with the verification fields when those ship. [Verified inference](https://ambient.xyz/docs/build/verified-inference) covers what the flags are for, the `verified` and `merkle_root` response fields, and their current status. ## Server-side tools and reasoning control Beyond the verification flags, the request schema declares further Ambient-specific fields: - `enabled_tools` turns on built-in, server-side tools that the network runs on your behalf, distinct from `tools`, which declares your own client-side function tools. The schema lists `websearch`, `retrieval`, `crypto_price`, `stock_price`, `weather`, `currency_convert`, and `calculator`; pass `["*"]` to enable all of them. - `reasoning` is a reasoning-control object: `enabled: false` turns thinking off (see [Short answers](#short-answers-turn-thinking-off)), and an optional `max_tokens` caps reasoning spend. It supersedes the older `thinking_budget` field, which the schema marks deprecated. `enabled` and the top-level `reasoning_effort` are accepted by the live API ahead of the schema snapshot listing them. - `emit_usage` requests a usage object in the response when set; the streaming equivalent is `stream_options: {"include_usage": true}`. As with the verification flags, confirm behavior against the specific model you target: capabilities are gated per model by `supported_features` and `supported_sampling_parameters` in [`GET /v1/models`](https://ambient.xyz/docs/build/api/models-endpoint). ### Short answers: turn thinking off GLM 5.2 (`ambient/large`) reasons before it answers, and `max_tokens` covers both. For a one-word or one-line reply, a small budget such as `60` comes back `200` with `"content": null`, `finish_reason: "length"`, the thinking in `message.reasoning`, and `usage.completion_tokens_details.reasoning_tokens` greater than zero. Rather than trimming `max_tokens`, disable thinking with any one of these: - Model id suffix `-nonthinking`, for example `"ambient/large-nonthinking"`. - `"reasoning": {"enabled": false}` in the request body. - `"reasoning_effort": "none"`. Each returns the plain answer in a handful of completion tokens. ```bash title="short-answer-request.sh" curl https://api.ambient.xyz/v1/chat/completions \ -H "Authorization: Bearer $AMBIENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ambient/large", "messages": [{"role": "user", "content": "Reply with one word: is 7 prime?"}], "reasoning": {"enabled": false}, "max_tokens": 512 }' ``` `reasoning_effort` values of `"low"`, `"medium"`, and `"high"` do not reduce GLM 5.2's thinking: it treats all three as `"high"`. Only `"none"` turns it off. `chat_template_kwargs.enable_thinking` has no effect either. Whichever route you take, still check `finish_reason` on every response. ## Response The spec declares the `ChatCompletionResponse` shape as `choices[].message` with the completion, a `usage` object with prompt, completion, and reasoning token counts, plus the verification fields `verified` and `merkle_root`. > [!WARNING] Live response shape > Responses currently contain the standard OpenAI fields plus engine > extras such as `system_fingerprint` and `token_ids`; `verified` and > `merkle_root` are not yet returned. Parse the standard fields and treat > the verification fields as optional. Every response also carries an `inference-id` response header (mirrored as `x-request-id`), a stable identifier for the request. Log it: it is the durable handle for the inference. Reasoning models return their thinking in `message.reasoning` (or, on some models, `reasoning_content`), separate from `message.content`. If `content` comes back `null` with `finish_reason: "length"`, the token budget was spent on reasoning; raise `max_tokens`, or for short answers [turn thinking off](#short-answers-turn-thinking-off). ## Streaming Set `"stream": true` for server-sent events, and `"stream_options": {"include_usage": true}` to get token counts in the final chunk. Chunks are standard OpenAI `chat.completion.chunk` objects, with reasoning deltas split across two possible keys depending on the model. [Streaming](https://ambient.xyz/docs/build/streaming) covers the mechanics, the dual delta keys, and stall/truncation detection. ## Errors [Errors and retries](https://ambient.xyz/docs/build/errors) covers the full taxonomy, including the two different meanings of `429` and why you should never blindly retry a timed-out completion POST. --- # Models endpoint > GET /v1/models reference. The unauthenticated catalog endpoint, per-model pricing and capability fields, and why is_ready is not an availability signal. - Canonical: https://ambient.xyz/docs/build/api/models-endpoint --- `GET /v1/models` returns the live model catalog: ids, pricing, context windows, and capabilities. Anything it lists is served. The endpoint reference is below; [Models and readiness](https://ambient.xyz/docs/build/models) is the guide to choosing a model from it. ### GET /v1/models List Models **Response (200) — ListModelsResponse** | Field | Type | Required | Description | | --- | --- | --- | --- | | `data` | ModelInfo[] | Yes | — | | `has_more` | boolean | — | — | | `object` | string | — | — | Current as of 2026-07-04; the live spec is at https://api.ambient.xyz/openapi.json. ## No auth required The model catalog is the one part of the API that works without an API key: ```bash curl https://api.ambient.xyz/v1/models ``` Two practical consequences: - You can call it from anywhere (scripts, dashboards, even browser JavaScript) without exposing a credential. - A successful call proves nothing about your key. The only way to validate a key is a real completion; the [quickstart](https://ambient.xyz/docs/get-started/quickstart) makes one. ## Reading a model entry `data` is an array of model objects. The fields that drive integration decisions: | Field | What it tells you | | --- | --- | | `id` | The exact string to pass as `model` in requests, a case-sensitive path like `z-ai/glm-5.2` | | `is_ready` | An OpenRouter routing flag (whether OpenRouter routes traffic to this model). Not whether the model is served: listed models answer requests regardless of its value | | `context_length` / `max_output_length` | Token limits for input window and generation | | `pricing.input` / `pricing.output` | USD per million tokens, as floats; the source of truth for cost | | `supported_features` | Capability switches: `tools`, `json_mode`, `structured_outputs`, `reasoning`, `logprobs` | | `supported_sampling_parameters` | Which sampling knobs the model accepts | | `quantization` | Serving precision (e.g. `fp8`, `int4`), when published | `is_ready` is consumed by OpenRouter's routing and says nothing about whether Ambient is serving the model, so don't gate model selection on it. Everything the catalog lists is served; if a model has no capacity when you call it, the request itself returns `429` with `"No workers available"` or `"Upstream request failed"` (retry with short, jittered backoff or fail over; see [Errors and retries](https://ambient.xyz/docs/build/errors)). A one-liner to list the ids you can request: ```bash curl -s https://api.ambient.xyz/v1/models | jq -r '.data[].id' ``` > [!NOTE] > The API does not expose a balance endpoint. Track credits and usage in > the Ambient app (Billing and Usage), or meter spend by combining each > response's `usage` token counts with the per-model `pricing` from this > endpoint. See [Errors and retries](https://ambient.xyz/docs/build/errors) for the related > error taxonomy. ## Single model lookup The same object is available per model id: ### GET /v1/models/{model_id} Get Model **Parameters** | Parameter | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `model_id` | path | string | Yes | — | **Response (200) — ModelInfo** | Field | Type | Required | Description | | --- | --- | --- | --- | | `context_length` | integer | Yes | — | | `created` | integer | Yes | — | | `id` | string | Yes | — | | `input_modalities` | string[] | Yes | — | | `max_output_length` | integer | Yes | — | | `name` | string | Yes | — | | `output_modalities` | string[] | Yes | — | | `pricing` | ModelPricing | Yes | — | | `supported_features` | string[] | Yes | — | | `supported_sampling_parameters` | string[] | Yes | — | | `datacenters` | DatacenterInfo[] \| null | — | — | | `description` | string \| null | — | — | | `hugging_face_id` | string \| null | — | — | | `is_ready` | boolean \| null | — | — | | `object` | string | — | — | | `openrouter` | OpenRouterInfo \| null | — | — | | `owned_by` | string | — | — | | `quantization` | string \| null | — | — | Current as of 2026-07-04; the live spec is at https://api.ambient.xyz/openapi.json. ```bash curl https://api.ambient.xyz/v1/models/z-ai/glm-5.2 ``` Model ids contain slashes and are used as literal path segments; the ids the catalog publishes today do not need URL encoding. --- # Pay per request with x402 > Pay-per-request inference through JumpGate and the x402 payment protocol. Quote an exact request, pay in USDC on Solana or Base, and stream the response. - Canonical: https://ambient.xyz/docs/build/x402 --- x402 lets a client pay for a single inference request with USDC, without an account or prepaid credits. Payments are live today on Solana and Base; the integration is a quote-then-pay flow against two JumpGate endpoints. ## Overview JumpGate supports pay-per-request AI inference through the [x402 payment protocol](https://www.x402.org/). Clients send a chat request, receive a quote for that exact request, then use an x402 client to pay with USDC and stream the response. | | | | --- | --- | | Recommended endpoint | `POST https://jumpgate.ambient.xyz/paid/chat/v2` | | Quote endpoint | `POST https://jumpgate.ambient.xyz/paid/chat/v2/quote` | New clients should use `/paid/chat/v2`. `/paid/chat` may remain available for older x402 v1 clients, but it is not the recommended integration path. Legacy vault-backed relayer endpoints are no longer the supported integration path. ## Supported payment networks JumpGate accepts these trusted USDC rails: | Network | Chain identifier | USDC token address | Trusted recipient | | --- | --- | --- | --- | | Solana mainnet | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | `AYYo37bgztqAgP6wp2S9SiYWcijr8gz2o14c8RGWojJZ` | | Base mainnet | `eip155:8453` | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | `0x6992c688c56be442efe1e1ce7d5c95212ed7d59b` | Validate network, asset, recipient, and amount before signing. Normalize Base addresses to lowercase before comparison; preserve case for Solana identifiers. Use Solana when you want lower network fees. Use Base when your application already has EVM wallet infrastructure. ## Prerequisites Before making a paid request, your client needs: - **Solana**: a Solana wallet with canonical mainnet USDC and access to a Solana mainnet RPC endpoint. The facilitator supplies the fee payer for the current exact-payment flow, so the buyer does not need SOL for the x402 transfer fee. - **Base**: an EVM wallet with canonical USDC on Base mainnet and access to a Base RPC endpoint. The EIP-3009 flow is gas-sponsored, so the buyer does not need ETH for the x402 transfer fee. - **TypeScript runtime**: browser or runtime support for `fetch`, readable response streams, and the wallet signing APIs you plan to use. ## How x402 works The x402 protocol uses the HTTP `402 Payment Required` response to negotiate payment for a normal HTTP request. For JumpGate: 1. Your client sends the paid chat request to JumpGate. 2. JumpGate returns x402 payment requirements for Solana and Base. 3. Your x402 client selects a supported network and signs the USDC payment. 4. The client retries the request with payment proof. 5. JumpGate verifies the payment and streams the inference response as SSE. The official x402 client libraries handle the payment negotiation and retry. Your application still controls the request body, pricing quote, wallet selection, and local spend cap. The exact package set this page is written against is pinned under [TypeScript client](#typescript-client). ## Request flow ```text 1. Build the inference request body. 2. POST the same body to /paid/chat/v2/quote, plus optional max_tool_calls. 3. Read quote.headers, amount fields, token counts, model_tier, and max spend fields. 4. POST the original inference request to /paid/chat/v2 with quote.headers copied unchanged. 5. Let the x402 client handle 402 -> sign/pay -> retry. 6. Read the final response as Server-Sent Events. ``` The quote endpoint uses the same chat tokenization and pricing validation as `/paid/chat/v2`, so clients should not estimate token counts locally. ## Quote request Send the same inference body you will send to `/paid/chat/v2`. Add `max_tool_calls` when your client wants to reserve budget for tool calls. ```json { "model": "ambient/large", "messages": [ { "role": "user", "content": "Explain verifiable inference in one paragraph." } ], "stream": true, "is_paid": true, "max_completion_tokens": 1000, "max_tool_calls": 0 } ``` Quote response: ```json { "headers": { "x402-input-tokens": "17", "x402-max-completion-tokens": "1000", "x402-model-tier": "standard", "x402-max-tool-calls": "0" }, "input_tokens": 17, "output_tokens": 1000, "model_tier": "standard", "max_tool_calls": 0, "amount_micro_usdc": 4424, "amount_usdc": 0.004424, "max_amount_micro_usdc": 4474, "max_amount_usdc": 0.004474 } ``` Copy `headers` unchanged into the paid chat request. Use `max_amount_micro_usdc` as the local spend cap for the x402 payment requirement. ## Pricing headers The quote response returns the pricing headers required by `/paid/chat/v2`: | Header | Meaning | | --- | --- | | `x402-input-tokens` | Chat-tokenized input count | | `x402-max-completion-tokens` | Requested maximum output tokens | | `x402-model-tier` | Model pricing tier, such as `standard` or `mini` | | `x402-max-tool-calls` | Maximum billable tool calls reserved for the request | Do not calculate these headers from byte length or character length. Request a quote and forward the returned values. For human-readable pricing, see [Ambient billing](https://app.ambient.xyz/billing). ## TypeScript client Use Node.js 20.18 or newer and pin the payment and wallet libraries used by the integration: ```bash npm install --save-exact @x402/core@2.11.0 @x402/fetch@2.11.0 @x402/svm@2.11.0 @x402/evm@2.11.0 viem@2.48.4 @solana/kit@5.5.1 @solana/web3.js@1.98.4 ``` > [!WARNING] Paid chat only > The automatic `wrapFetchWithPayment` example below is for account-free > `/paid/chat/v2` calls. Never use this wrapper for a headless subscription > `payment_url`; subscription clients must durably save one authorization and > transmit it only once. See > [headless x402 subscriptions](https://ambient.xyz/docs/build/x402-subscriptions) for that flow. Shared request and quote helpers: ```ts const JUMPGATE_URL = 'https://jumpgate.ambient.xyz'; const PAID_CHAT_URL = `${JUMPGATE_URL}/paid/chat/v2`; const QUOTE_URL = `${PAID_CHAT_URL}/quote`; const request = { model: 'ambient/large', messages: [{ role: 'user', content: 'Hello from x402.' }], stream: true, is_paid: true, max_completion_tokens: 1000 }; async function quoteChat(request: unknown) { const response = await fetch(QUOTE_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...request, max_tool_calls: 0 }) }); if (!response.ok) throw new Error(await response.text()); return await response.json(); } ``` Payment and streaming helper. The `registerPolicy` filter is the local spend cap: it rejects any payment requirement that is not the exact scheme, not a trusted asset and recipient, or above `quote.max_amount_micro_usdc`. ```ts import { x402Client } from '@x402/core/client'; import { wrapFetchWithPayment } from '@x402/fetch'; const TRUSTED_RAILS: Record = { 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': { asset: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', payTo: 'AYYo37bgztqAgP6wp2S9SiYWcijr8gz2o14c8RGWojJZ' }, 'eip155:8453': { asset: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', payTo: '0x6992c688c56be442efe1e1ce7d5c95212ed7d59b' } }; type PaymentRequirement = { network: string; scheme: string; asset: string; payTo: string; amount?: string; maxAmountRequired?: string; }; function paymentAmountMicroUsdc(requirement: PaymentRequirement) { return BigInt(requirement.amount ?? requirement.maxAmountRequired ?? 0); } function isTrustedRequirement(requirement: PaymentRequirement, maxAmount: bigint) { const rail = TRUSTED_RAILS[requirement.network]; if (!rail || requirement.scheme !== 'exact') return false; const normalize = (value: string) => requirement.network.startsWith('eip155:') ? value.toLowerCase() : value; const amount = paymentAmountMicroUsdc(requirement); return ( normalize(requirement.asset) === normalize(rail.asset) && normalize(requirement.payTo) === normalize(rail.payTo) && amount > 0n && amount <= maxAmount ); } async function streamPaidChat({ quote, request, registerScheme }: { quote: { max_amount_micro_usdc?: string; amount_micro_usdc: string }; request: unknown; registerScheme: (client: x402Client) => void; }) { const client = new x402Client(); const maxAmount = BigInt(quote.max_amount_micro_usdc ?? quote.amount_micro_usdc); client.registerPolicy((_version: number, requirements: PaymentRequirement[]) => requirements.filter((requirement) => isTrustedRequirement(requirement, maxAmount)) ); registerScheme(client); const fetchWithPayment = wrapFetchWithPayment(fetch, client); const response = await fetchWithPayment(PAID_CHAT_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'text/event-stream', ...quote.headers }, body: JSON.stringify(request) }); if (!response.ok) throw new Error(await response.text()); for await (const payload of readSse(response)) { console.log(payload); } } ``` SSE parser: ```ts async function* readSse(response: Response) { const reader = response.body?.getReader(); if (!reader) throw new Error('Response body is not readable.'); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const frames = buffer.split(/\r?\n\r?\n/); buffer = frames.pop() || ''; for (const frame of frames) { const data = frame .split(/\r?\n/) .filter((line) => line.startsWith('data:')) .map((line) => line.slice(5).trimStart()) .join('\n'); if (data && data !== '[DONE]') yield JSON.parse(data); } } } ``` ### Solana signer Use a connected Solana wallet that can sign transactions. ```ts import { getBase64EncodedWireTransaction, address as solanaAddress } from '@solana/kit'; import { VersionedTransaction } from '@solana/web3.js'; import { toClientSvmSigner } from '@x402/svm'; import { registerExactSvmScheme } from '@x402/svm/exact/client'; function createSolanaSigner(provider, publicKeyString: string) { return toClientSvmSigner({ address: solanaAddress(publicKeyString), signTransactions: async (transactions) => await Promise.all( transactions.map(async (transaction) => { const encoded = getBase64EncodedWireTransaction(transaction); const web3Transaction = VersionedTransaction.deserialize(base64ToBytes(encoded)); const signed = await provider.signTransaction(web3Transaction); const signerIndex = signed.message.staticAccountKeys.findIndex( (key) => key.toBase58() === publicKeyString ); return Object.freeze({ [publicKeyString]: signed.signatures[signerIndex] }); }) ) }); } const solanaSigner = createSolanaSigner(window.solana, window.solana.publicKey.toBase58()); const quote = await quoteChat(request); await streamPaidChat({ quote, request, registerScheme: (client) => registerExactSvmScheme(client, { signer: solanaSigner }) }); ``` ### Base signer Use a Base-compatible EVM wallet. Switch to Base before signing. ```ts import { createPublicClient, createWalletClient, custom, http } from 'viem'; import { base } from 'viem/chains'; import { toClientEvmSigner } from '@x402/evm'; import { registerExactEvmScheme } from '@x402/evm/exact/client'; type Eip1193Provider = { request: (args: { method: string; params?: unknown[] }) => Promise; }; async function createBaseSigner(provider: Eip1193Provider) { await provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0x2105' }] }); const walletClient = createWalletClient({ chain: base, transport: custom(provider) }); const [account] = await walletClient.requestAddresses(); const publicClient = createPublicClient({ chain: base, transport: http('https://mainnet.base.org') }); return toClientEvmSigner( { address: account, signTypedData: (message) => walletClient.signTypedData({ account, ...message }) }, publicClient ); } const baseSigner = await createBaseSigner(window.ethereum); const quote = await quoteChat(request); await streamPaidChat({ quote, request, registerScheme: (client) => registerExactEvmScheme(client, { signer: baseSigner, networks: ['eip155:8453'], schemeOptions: { 8453: { rpcUrl: 'https://mainnet.base.org' } } }) }); ``` ## Response format Successful paid chat responses stream Server-Sent Events: ```text data: {"Content":{"choices":[{"delta":{"content":"Hello"}}]}} data: {"Usage":{"usage":{"prompt_tokens":5,"completion_tokens":10,"total_tokens":15}}} data: {"Verification":{"verified":true}} data: [DONE] ``` Handle at least these event types: | Event | Contents | | --- | --- | | `Content` | Streamed model output | | `Usage` | Token usage and verification metadata when requested | | `Verification` | Payment or inference verification status when requested | | `[DONE]` | Stream complete | ## Testing and debugging Before sending a real paid request, check that the selected wallet holds enough canonical USDC. Base EIP-3009 and the current Solana exact-payment flow use facilitator-sponsored transaction fees, so the buyer does not need ETH or SOL for the x402 transfer fee. Solana USDC balance: ```bash spl-token balance EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v --url mainnet-beta ``` Base USDC balance: ```bash cast call 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \ "balanceOf(address)(uint256)" \ --rpc-url https://mainnet.base.org ``` Common issues: - **Insufficient funds**: add canonical USDC for the payment amount. - **Wrong network**: use Solana mainnet or Base mainnet only; devnet and testnet are not supported. - **Payment rejected**: confirm the wallet, network, canonical asset, trusted recipient, USDC balance, and local max-spend policy. - **`403 Forbidden`**: payment was rejected or below the facilitator requirement. - **`402 Payment Required` is returned to your app**: confirm the x402 wrapper is installed, the exact Solana or EVM scheme is registered, and the request includes the quote headers. - **`429` or `503` before authorization**: back off and retry the quote or unsigned request. > [!CAUTION] Failures after authorization are ambiguous > Any failure that arrives after an authorization may have been transmitted. > Capture the raw response and do not automatically invoke the wrapper again or > create another authorization. Subscription clients should follow the > [headless x402 subscriptions](https://ambient.xyz/docs/build/x402-subscriptions) classifications: > every post-transmission non-success stops automatic retries, but recognized > pre-broadcast rejection and confirmed non-submission are distinct from a > funds-at-risk unknown outcome. ## Production notes - Use a local max spend policy based on `quote.max_amount_micro_usdc`. - Use HTTPS RPC endpoints from a reliable provider for production clients. - Keep private keys out of source control and prefer wallet adapters or secure key management. - Log payment status, request status, response latency, and selected payment network. - Do not reuse quote headers for a different request body. ## FAQ ### Do I need an account or API key? No. Account-free paid-chat requests need only a compatible wallet with canonical USDC. The facilitator sponsors the transaction fee for the supported Base EIP-3009 and Solana exact-payment flows. ### Which networks are supported? Solana mainnet and Base mainnet. ### Which token is supported? USDC only. ### Can I use devnet or testnet? No. JumpGate x402 payments are supported on mainnet only. ### Which endpoint should new clients use? Use `/paid/chat/v2`. `/paid/chat` may exist for older x402 v1 clients, but it is compatibility-only. ### How should I limit spend? Call `/paid/chat/v2/quote` first and enforce a local max spend using `quote.max_amount_micro_usdc`. Do not estimate pricing locally. ## Additional resources - [x402 protocol](https://www.x402.org/): the specification this flow implements - [x402 buyer quickstart](https://docs.x402.org/getting-started/quickstart-for-buyers): upstream client-side walkthrough - [Ambient billing](https://app.ambient.xyz/billing): human-readable pricing ## Related x402 flow - [Headless x402 subscriptions](https://ambient.xyz/docs/build/x402-subscriptions): create and fund an API-only Ambient account for ongoing inference without a browser login. - [Subscription client example](https://ambient.xyz/docs/build/x402-subscriptions-example): a worked subscribe-then-call client for that flow. ## Related pages - [Solana quickstart](https://ambient.xyz/docs/build/solana-quickstart): Ambient's Solana-compatible RPC and SVM tooling - [Models and readiness](https://ambient.xyz/docs/build/models): what the network is serving right now - [Streaming](https://ambient.xyz/docs/build/streaming): SSE mechanics for reading the paid response --- # Headless x402 subscriptions > Register, obtain and validate a live offer, authorize and pay, complete provisioning, use the account, and renew an API-only Ambient subscription headlessly over x402. - Canonical: https://ambient.xyz/docs/build/x402-subscriptions --- External clients can create and fund an API-only Ambient account without an email, browser login, wallet login, or the Ambient UI. The Ambient API key is the account credential. A wallet is used only to authorize the x402 payment. See the [restart-safe TypeScript x402 subscription example](https://ambient.xyz/docs/build/x402-subscriptions-example) for a working client. The integration has six steps: 1. Register with `POST /billing/x402/register-and-subscribe`. 2. Securely save the one-time-displayed API key before paying. 3. Send the opaque `payment_url` with an x402 v2 client and select a live Solana or Base offer. 4. Save the payment receipt and both Ambient grant headers, then call `POST /billing/x402/subscription-complete`. 5. Use the API key for inference and key management. 6. Use the same API key to create future renewal intents. The billing API origin is `https://api.ambient.xyz`. After provisioning, configure OpenAI-compatible clients with: ```text Base URL: https://api.ambient.xyz/v1 Authorization: Bearer ``` Supported inference endpoints include `POST /responses`, `POST /chat/completions`, and `GET /models` relative to that base URL. ## Credentials and addresses - **Ambient API key:** bearer credential for the API-only Ambient account; it never authorizes a blockchain transfer. - **Wallet private key or signer:** authorizes the x402 payment and stays inside the client's secure wallet boundary. Never send it to Ambient or Jumpgate. - **Payer address:** public wallet address recorded in the settlement receipt; it is payment metadata, not an Ambient login. - **USDC asset:** the Base token contract or Solana mint identifying the accepted currency. - **Payment recipient (`payTo`):** public Base or Solana address receiving USDC. Validate it against the trusted allowlist below. - **Ambient grant and signature:** short-lived opaque credentials proving a settled order to the completion endpoint; they are not API keys. If you need one-off inference without creating an account or API key, use the separate [account-free x402 client flow](https://ambient.xyz/docs/build/x402). ## Plans, duration, and expiry Supported `plan_id` values are: - `starter` - `basic` - `power` - `pro` See [Ambient pricing](https://ambient.xyz/pricing/) for current monthly prices and plan allowances. The signed order and live `402` determine the exact amount for a purchase. `months` is an integer from `1` through `12` and defaults to `1`. A bulk purchase is charged at the monthly price multiplied by `months`; there is no bulk discount. Each month is provisioned as a consecutive monthly period so its allowance resets independently. Renewals must use the plan at the account's farthest paid-through boundary. Ambient rejects a different plan before creating a payment order. When an order is created, all nonexpired current and future periods, unexpired pending orders, and the requested purchase may not exceed 12 months in total. A valid grant settled earlier can exceptionally take the account past that cap if it completes later; Ambient honors paid value instead of discarding the settlement. Registration and renewal payment URLs expire after 24 hours. That is not the payment authorization lifetime: create the authorization immediately before transmission and obey the shorter live rail-specific validity window. Base challenges currently use a 300-second authorization window; Solana blockhash validity is shorter and dynamic. A grant created by a successful settlement expires after seven days. An expired pending order becomes eligible for cleanup eight days after its payment URL expired; cleanup is asynchronous, so do not use retention as a payment or completion deadline. ## Client safety Persist the registration response and API key before paying. Serialize concurrent payment attempts and maintain at most one live or possibly transmitted authorization for an order. An expired authorization may be replaced only when durable state proves it was never marked attempted; never replace one after transmission was attempted or became ambiguous. > [!CAUTION] Never auto-retry a paid request > Jumpgate performs bounded, byte-identical retries for transient facilitator > failures. Those internal retries do not make it safe for the client to send > the paid request again. Do not run a paid request through generic `5xx` or > `Retry-After` retry middleware. After a paid request may have been > transmitted, never automatically resend it, create a replacement > authorization, or create a replacement order. Persist the raw response status and headers, including any receipt and grant, as soon as `fetch` resolves; read and store the body afterward as diagnostic data. Jumpgate is stateless, and Ambient does not expose a public settlement-status or grant-recovery endpoint. For compile-tested TypeScript reference code with injected signer, durable storage, and locking boundaries, see [Restart-safe TypeScript x402 subscription example](https://ambient.xyz/docs/build/x402-subscriptions-example). ## Lifecycle ### 1. Register Registration is public and does not use an Ambient credential: ```http POST https://api.ambient.xyz/billing/x402/register-and-subscribe Content-Type: application/json { "plan_id": "basic", "months": 3 } ``` A successful request returns `201 Created` and `Cache-Control: no-store`: ```json { "api_key": "<50-character Ambient API key>", "order_id": "7592578c-37b3-441e-a97c-7d262ebc0a72", "plan_id": "basic", "months": 3, "payment_url": "https://jumpgate.ambient.xyz/paid/subscription/v2/basic/3/7592578c-37b3-441e-a97c-7d262ebc0a72?intent=", "expires_at": "", "completion_url": "/billing/x402/subscription-complete" } ``` > [!WARNING] The API key is displayed once > Persist the complete response before paying, especially `api_key` and the > opaque `payment_url`. Ambient displays the API key only once and stores > only its prefix and SHA-256 hash. The key returns `401 Unauthorized` until > provisioning completes. Registration creates a pending order containing the bootstrap key prefix and hash. It does not create the API-only team, activate the key, or add subscription periods until a valid paid grant completes atomically. Registration is not idempotent: every successful call creates a distinct order and bootstrap key. A `429 Too Many Requests` response includes `Retry-After`. Only create a replacement order before any payment authorization has been created for the previous order; unexpired pending renewal orders also reserve months against the 12-month cap. When x402 sales are paused, registration and renewal intent creation return `403 Forbidden`. Completion remains available so a valid saved grant for a payment already made can still provision idempotently; a sales pause is not a reason to abandon that grant. Do not parse, reconstruct, shorten, or change `payment_url`. The signed intent binds the order, plan, duration, amount, and expiry. ### 2. Obtain and validate the live offer Send an empty unsigned `POST` to the opaque `payment_url` with redirects disabled. A valid challenge returns `402 Payment Required` with a base64-encoded x402 v2 object in `Payment-Required`. Ambient supports these USDC rails when they appear in the live response: | Network | CAIP-2 identifier | Canonical USDC asset | Accepted recipient | | --- | --- | --- | --- | | Solana mainnet | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | `AYYo37bgztqAgP6wp2S9SiYWcijr8gz2o14c8RGWojJZ` | | Base mainnet | `eip155:8453` | `0x833589fcd6edb6e08f4c7c32d4f71b54bda02913` | `0x6992c688c56BE442EfE1E1cE7D5c95212ED7d59B` | The live `accepts` array is authoritative for currently available rails and amounts, but it is not by itself a trusted recipient allowlist. A client must fail closed unless the selected offer satisfies all of these conditions: - `x402Version` is `2`. - `scheme` is `exact`. - `network`, `asset`, and `payTo` match one allowed rail above. For Base, normalize both addresses to lowercase before comparison because a live challenge may use checksum casing. Compare Solana identifiers exactly because they are case-sensitive. - `amount` is a canonical positive base-10 integer string. Parse it with `BigInt` or an equivalent checked integer type, require every offered rail to have the same value, and enforce the client's configured or user-approved maximum. - The resource identifies the intended Jumpgate payment URL. Do not accept an arbitrary `payTo` from the live challenge. Configure or publish the trusted recipients above with the client, and update that allowlist before paying a rotated recipient. The challenge itself is not signed and does not let the client select Jumpgate's configured facilitator. Choose one offered rail supported by the wallet. Do not create a payment payload merely to inspect the offer. ### 3. Authorize and pay Use the linked TypeScript reference for the exact package pins and injected Base or Solana signer boundary. Do not use an automatic paid-fetch wrapper for a subscription `payment_url`. ```bash npm install --save-exact @x402/core@2.11.0 @x402/evm@2.11.0 @x402/svm@2.11.0 viem@2.48.4 @solana/kit@5.5.1 ``` For each order: 1. Create or reuse one current authorization under the per-order lock. Replace an expired one only when durable state proves it was never attempted. 2. Persist its exact encoded `Payment-Signature` before transmission when the client supports a pre-send hook. 3. Send an empty `POST` to the exact saved `payment_url`, with redirects disabled, the saved `Payment-Signature`, and a timeout of at least 125 seconds. 4. As soon as `fetch` resolves, persist the raw status and all headers, including any `Payment-Response` and Ambient grants. Only then read and store the body as best-effort diagnostic data. Capture headers on non-`2xx` responses too. Subscription settlement happens before Jumpgate creates the grant and attempts Ambient's callback. The longer timeout covers facilitator discovery, settlement, confirmation, and the bounded synchronous callback attempts; a shorter client timeout can turn a successful on-chain payment into an ambiguous client result. A successful Jumpgate response is `200 OK` with this JSON shape: ```json { "order_id": "7592578c-37b3-441e-a97c-7d262ebc0a72", "plan_id": "basic", "months": 3, "amount_micro_usdc": 60000000 } ``` The numeric amount is illustrative; the validated live offer is authoritative. Save these response headers: ```text Payment-Response X-Ambient-X402-Grant X-Ambient-X402-Grant-Signature ``` `X-Payment-Response` may be accepted as a legacy fallback when `Payment-Response` is absent. New integrations should use the standard `Payment-Response` header. Header names are case-insensitive. The selected network, payer, and transaction are in the payment response and the signed grant, not the JSON response body. Before treating the payment as successful, require: - HTTP status `200`. - A decoded settlement receipt with `success=true`. - A nonempty payer and transaction. - A network matching the selected offer. - A payer matching the expected signer address; normalize Base addresses to lowercase and compare Solana addresses exactly. - If the receipt includes `amount`, an amount matching the selected offer. Receipt amount is optional, so absence alone is not an error. - Both Ambient grant headers. The unsigned JSON response body is diagnostic only and is not proof of settlement or provisioning. Treat the grant headers as opaque credentials. The signed grant binds the order, plan, months, amount, selected network, canonical asset, configured recipient, payer, transaction, issue time, and expiry. Base identifiers are normalized to lowercase; Solana identifiers remain case-sensitive. Jumpgate starts Ambient's completion callback independently of the downstream connection and normally waits for it, retrying only transient failures. Callback rejection or exhaustion still returns the valid grant and `200`; explicit client completion remains required. A downstream timeout or disconnect does not cancel that tracked callback or itself prove payment failure. An unsigned request or a header rejected before authorization acceptance returns `402 Payment Required` with a `Payment-Required` challenge. A missing, expired, or path-mismatched Ambient intent returns `400 Bad Request` before payment handling. Once the saved authorization may have been transmitted, do not infer from a status code or intermediary-generated error page that settlement did not occur. Treat every non-success after the authorization may have been transmitted as terminal for automatic payment handling. The outcome is unknown and funds may be at risk if any of these occur: - A timeout, disconnect, or other transport loss. - A challenge-free non-success without a structured `facilitator_rejected` or `settlement_unavailable` classification. - A `200` with an invalid or unsuccessful receipt. - A missing grant header, empty payer or transaction, network mismatch, or a present receipt amount that mismatches the selected offer. Jumpgate uses `409 Conflict`, `X-Ambient-X402-Error-Code: AMBIGUOUS_X402_SETTLEMENT`, and the shared error code as a compatibility envelope for all structured post-authorization failures. Every variant stops automatic retries, but only `payment_status=unknown` or `payment_status=facilitator_reported_success` indicates funds may be at risk. When Jumpgate cannot confirm settlement, its JSON body includes bounded context that is safe to persist or display: ```json { "code": "AMBIGUOUS_X402_SETTLEMENT", "error": "Payment settlement outcome is ambiguous; do not create another payment authorization.", "order_id": "7592578c-37b3-441e-a97c-7d262ebc0a72", "phase": "settlement", "reason": "settlement_unconfirmed", "payment_status": "unknown", "next_action": "do_not_create_new_authorization" } ``` When the facilitator reports a recognized pre-broadcast validation rejection without a settlement identifier, Jumpgate keeps the same challenge-free compatibility response but distinguishes it from an unknown outcome: ```json { "code": "AMBIGUOUS_X402_SETTLEMENT", "error": "Payment settlement failed; do not create another payment authorization automatically.", "order_id": "7592578c-37b3-441e-a97c-7d262ebc0a72", "phase": "settlement", "reason": "facilitator_rejected", "facilitator_reason": "insufficient_funds", "payment_status": "facilitator_reported_failure", "next_action": "do_not_create_new_authorization" } ``` `facilitator_reason` is optional and limited to `insufficient_funds`, `authorization_not_yet_valid`, `authorization_expired`, `invalid_authorization`, `payment_mismatch`, `transaction_rejected`, `unsupported`, or `invalid_response`. It reports the facilitator's bounded classification, not independent proof of the on-chain outcome. A missing, unrecognized, or conflicting reason, or a failure carrying a transaction or legacy signature, is classified as `settlement_unconfirmed` with `payment_status=unknown`. If Jumpgate proves that a local failure happened before it submitted the authorization to the facilitator, the same `409` instead uses `reason=settlement_unavailable` and `payment_status=not_submitted`. This does not trigger Ambient's payment-risk pager, but the client must still preserve the saved authorization and stop automatic payment handling. For other failures, `phase` is `settlement`, `receipt_validation`, or `post_settlement`. Receipt-validation reasons are limited to `missing_receipt`, `missing_network`, `missing_payer`, `missing_transaction`, and `unsupported_network`; post-settlement processing uses `post_settlement_failure`. `payment_status=facilitator_reported_success` means the facilitator reported success but does not replace the requirement to validate and persist `Payment-Response`. Jumpgate does not put raw facilitator errors, payer or transaction identifiers, payment credentials, or grants in this JSON body. Ambient's operational pager is narrower than the client's safety rule. It fires only when Jumpgate cannot determine the settlement outcome, cannot turn a reported success into a valid grant, or the Ambient callback is rejected or exhausts its retries. A downstream client timeout or disconnect does not page by itself or cancel an already-started callback; if that callback succeeds, the account is provisioned even when the client did not receive the response. Treat `next_action=do_not_create_new_authorization` as authoritative. An intermediary-generated response such as a Cloudflare `524` cannot contain these Jumpgate fields, so the broader challenge-free safety rule still applies. Do not follow `Retry-After`, invoke generic HTTP retries, resend the paid request, or create a replacement authorization after any post-transmission non-success. A genuine pre-payment retry remains safe only when the response is a normal `402` carrying a valid `Payment-Required` challenge and the client has not transmitted an authorization. ### 4. Complete provisioning Resolve the relative `completion_url` against `https://api.ambient.xyz`, not the `/v1` inference base. The endpoint is public: the signed grant is its authorization, so do not send the bootstrap API key. ```http POST https://api.ambient.xyz/billing/x402/subscription-complete Content-Type: application/json { "grantToken": "", "signature": "" } ``` A successful completion returns: ```json { "team_id": "344740c2-fcb4-470f-8c88-721765743b67", "plan_id": "basic", "months": 3, "current_period_end": "", "already_completed": true } ``` Completion is idempotent for the same order and payment. Always call it after receiving a grant, even if Jumpgate's callback may already have provisioned the account. `already_completed` is normally `true` when that callback succeeded and `false` when the client performed the first successful provisioning. Repeating the same order and payment never adds more months. A still-valid seven-day grant can complete after the original 24-hour payment URL expires. Complete promptly instead of relying on the retention window. Treat a completion `409 Conflict` as a terminal reconciliation case; do not try another payment. ### 5. Use the account Example activation and usage check: ```http GET https://api.ambient.xyz/billing/usage-summary Authorization: Bearer ``` After provisioning, the response is authenticated and reports the expected active subscription. Before provisioning, the bootstrap key returns `401 Unauthorized`. Example model listing: ```http GET https://api.ambient.xyz/v1/models Authorization: Bearer ``` Example Chat Completions request: ```http POST https://api.ambient.xyz/v1/chat/completions Authorization: Bearer Content-Type: application/json { "model": "", "messages": [{"role": "user", "content": "Hello"}] } ``` The same API key can use the Responses API and manage additional Ambient API keys through these routes: - `GET https://api.ambient.xyz/keys` - `POST https://api.ambient.xyz/keys` - `PATCH https://api.ambient.xyz/keys/{prefix}` - `DELETE https://api.ambient.xyz/keys/{prefix}` These routes use `Authorization: Bearer ` and resolve against `https://api.ambient.xyz`, not the `/v1` inference base. ### 6. Renew Create a renewal intent with any API key belonging to the account: ```http POST https://api.ambient.xyz/billing/x402/subscription-intent Authorization: Bearer Content-Type: application/json { "planId": "basic", "months": 2 } ``` `planId` is the canonical example field; the API also accepts the compatibility spelling `plan_id`. The response contains another opaque payment URL: ```json { "order_id": "bb26e7f0-ef27-4dde-a6b7-35ad2e13f0fe", "plan_id": "basic", "months": 2, "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", "payment_url": "https://jumpgate.ambient.xyz/paid/subscription/v2/basic/2/bb26e7f0-ef27-4dde-a6b7-35ad2e13f0fe?intent=" } ``` `network` is a legacy Solana compatibility hint, not a complete list of available rails. Select a rail from the live `402` response. Pay and complete the renewal through the same payment, grant-persistence, and completion steps as registration. The bootstrap-key activation probe used for initial registration does not apply to renewals. The new periods begin at the account's farthest paid-through boundary. Renewal intent creation is not idempotent. An active Stripe subscription or another non-x402 subscription cannot be extended through this endpoint; Ambient returns `409 Conflict`. ## Ambiguous results If both saved grant headers are available, submit them to the idempotent completion endpoint. For initial registration, `GET /billing/usage-summary` with the saved bootstrap key can confirm whether the callback activated the account. A successful authenticated response reporting the expected active plan confirms activation; `401 Unauthorized` means the key remains inactive. This check cannot prove a renewal completed because the account was already active before renewal. If no grant is available and activation cannot be confirmed, do not automatically resend the payment, generate another authorization, or create a replacement order. Stop and contact [support@ambient.xyz](mailto:support@ambient.xyz) for reconciliation. For support, provide only: - Order ID. - Payment rail/network. - Payer address. - Transaction ID or EVM authorization nonce. > [!CAUTION] Never share a secret with support > Never provide an Ambient API key, `Payment-Signature`, > `X-Ambient-X402-Grant`, `X-Ambient-X402-Grant-Signature`, wallet private > key, seed phrase, or other secret. Support must verify payment and account > activation independently; a confirmed duplicate or paid-without-provisioning > result may require a refund. ## Current limitations - Renewal is manual; there is no unattended auto-renewal. - API-only accounts cannot log into the Ambient web UI. Losing every API key means losing account access; there is no email, wallet-signature, or browser recovery flow. - Jumpgate is stateless and exposes no public settlement-status or grant-recovery endpoint. - The callback is best effort. Deterministic client completion remains required. - There is no cancellation or modification endpoint for a pending order. - Two independently authorized transactions can still pay the same order. Ambient detects the second receipt but cannot prevent the second on-chain transfer; support reconciliation may be required. - Settlement can succeed immediately before a Jumpgate crash loses both the paid response and callback, requiring manual reconciliation or refund. - A late valid settlement can exceptionally take the account above the normal 12-month prepaid cap because Ambient honors paid value. ## Related pages - [Pay per request with x402](https://ambient.xyz/docs/build/x402): the account-free, quote-then-pay flow for a single inference request - [Restart-safe TypeScript x402 subscription example](https://ambient.xyz/docs/build/x402-subscriptions-example): compile-tested client with injected signer, durable storage, and locking - [Models and readiness](https://ambient.xyz/docs/build/models): what the network is serving right now --- # Restart-safe x402 subscriptions in TypeScript > A durable-state TypeScript reference implementation of the Ambient x402 subscription flow that survives a process restart at every stage, from unsigned challenge to completed provisioning. - Canonical: https://ambient.xyz/docs/build/x402-subscriptions-example --- This reference shows the payment-critical parts of an Ambient headless subscription client. Use the [Headless x402 subscriptions guide](https://ambient.xyz/docs/build/x402-subscriptions) for endpoint examples, supported plans, account usage, key management, and current limitations. See [Ambient pricing](https://ambient.xyz/pricing/) before choosing a client-side spending limit. > [!WARNING] Status > This page is a compile-tested reference, not a drop-in CLI. The integrator > must provide a secure wallet signer, a durable transactional store, and a > cross-process per-order lock. Registration creates a pending order and stores only the bootstrap key's prefix and hash. It does **not** create a team, usable API-key row, or subscription policy. Ambient creates those together when a valid settled grant completes. A renewal order uses the same payment state but has no bootstrap key. Ambient's 12-month limit counts nonexpired current and future policies, unexpired pending-order months, and the requested months. Do not create speculative renewal intents: each live intent reserves capacity. ## Tested versions Use Node.js 20.18 or newer and pin the payment stack. `viem` and `@solana/kit` are signer-adapter dependencies; omit a rail's unused wallet package from a single-rail client. ```bash npm install --save-exact \ @x402/core@2.11.0 \ @x402/evm@2.11.0 \ @x402/svm@2.11.0 \ viem@2.48.4 \ @solana/kit@5.5.1 ``` Do not use an automatic paid-fetch wrapper for a subscription payment URL. The client must durably save one exact authorization before transmitting it and must not let generic HTTP retry middleware repeat the paid request. ## Durable state and injected boundaries The types below work for both registration and renewal. Construct `PaymentOrder.bootstrap` only from a registration response. Validate a registration response's `completion_url` is `/billing/x402/subscription-complete`, but always submit grants to the fixed HTTPS endpoint used below. Renewal requests accept the canonical `planId` field and the compatibility alias `plan_id`. ```ts import { x402Client } from "@x402/core/client"; import { decodePaymentRequiredHeader, decodePaymentResponseHeader, encodePaymentSignatureHeader, } from "@x402/core/http"; import type { PaymentPayload, PaymentRequired, PaymentRequirements, SettleResponse, } from "@x402/core/types"; import { ExactEvmScheme, type ClientEvmSigner } from "@x402/evm"; import { ExactSvmScheme, type ClientSvmSigner } from "@x402/svm"; const API_ORIGIN = "https://api.ambient.xyz"; const COMPLETION_URL = `${API_ORIGIN}/billing/x402/subscription-complete`; const SOLANA = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"; const SOLANA_USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; const SOLANA_RECIPIENT = "AYYo37bgztqAgP6wp2S9SiYWcijr8gz2o14c8RGWojJZ"; const BASE = "eip155:8453"; const BASE_USDC = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"; const BASE_RECIPIENT = "0x6992c688c56be442efe1e1ce7d5c95212ed7d59b"; type Network = typeof SOLANA | typeof BASE; type TrustedOffer = PaymentRequirements & { network: Network }; type PlanId = "starter" | "basic" | "power" | "pro"; type Stage = | "registered" | "approved" | "authorized" | "attempted" | "granted" | "completed" | "ambiguous"; type PaymentOrder = { kind: "registration" | "renewal"; orderId: string; planId: PlanId; months: number; paymentUrl: string; bootstrap?: { apiKey: string; orderExpiresAt: string; }; }; type Approval = { orderId: string; planId: PlanId; months: number; resourceUrl: string; scheme: "exact"; network: Network; asset: string; recipient: string; amountMicroUsdc: string; expectedPayer: string; approvedAt: string; }; type PaidResponse = { status: number; headers: Record; paymentResponse?: string; grantToken?: string; grantSignature?: string; body?: string; }; type Completion = { team_id: string; plan_id: PlanId; months: number; current_period_end: string; already_completed: boolean; }; type OrderState = { stage: Stage; order: PaymentOrder; paymentRequiredHeader?: string; paymentRequired?: PaymentRequired; selectedOffer?: PaymentRequirements; approval?: Approval; paymentPayload?: PaymentPayload; paymentSignature?: string; transmissionAttemptedAt?: string; paidResponse?: PaidResponse; settlementReceipt?: SettleResponse; completion?: Completion; ambiguityReason?: string; }; type StoredState = { revision: number; value: OrderState }; interface DurableOrderStore { // This lock must exclude writers in every process, not only this Node process. withExclusiveLock(orderId: string, fn: () => Promise): Promise; read(orderId: string): Promise; // Atomically commits and returns the new revision, or throws on a mismatch. compareAndSwap( orderId: string, expectedRevision: number, next: OrderState, ): Promise; } type WalletChoice = | { network: typeof BASE; signer: ClientEvmSigner } | { network: typeof SOLANA; signer: ClientSvmSigner }; function assertOrderIdentity(orderId: string, state: OrderState): void { if (state.order.orderId !== orderId) { throw new Error("Loaded state belongs to a different order"); } } ``` `compareAndSwap` must be durable before it returns. A filesystem implementation needs an atomic same-directory replacement, file and directory flushes, owner-only permissions, and a lock identity that survives replacement. A database implementation should use a row lock or equivalent transaction. Never log the API key, payment signature, grant, wallet material, or complete stored response headers. ## Preview, validate, and record approval The live `402` is authoritative for availability and amount, but it is not a trusted recipient list. The selected offer must match the allowlist below. Base addresses compare lowercase; Solana identifiers remain case-sensitive. The Base checks require EIP-3009, canonical USDC's EIP-712 domain, and a positive authorization lifetime no longer than the currently trusted 300-second maximum. ```ts type Preview = { paymentRequiredHeader: string; paymentRequired: PaymentRequired; selectedOffer: TrustedOffer; }; function positiveAmount(value: unknown): bigint { if (typeof value !== "string" || !/^[1-9][0-9]*$/.test(value)) { throw new Error("Amount must be a canonical positive decimal integer"); } return BigInt(value); } function formatMicroUsdc(amount: bigint): string { const whole = amount / 1_000_000n; const fraction = (amount % 1_000_000n) .toString() .padStart(6, "0") .replace(/0+$/, ""); return fraction ? `${whole}.${fraction}` : whole.toString(); } function canonicalIdentifier(network: Network, value: string): string { const trimmed = value.trim(); if (!trimmed) throw new Error("Identifier is empty"); return network === BASE ? trimmed.toLowerCase() : trimmed; } function isTrustedOffer(offer: PaymentRequirements): offer is TrustedOffer { if (offer.scheme !== "exact") return false; if (offer.network === SOLANA) { return offer.asset === SOLANA_USDC && offer.payTo === SOLANA_RECIPIENT; } if (offer.network === BASE) { return ( offer.asset.toLowerCase() === BASE_USDC && offer.payTo.toLowerCase() === BASE_RECIPIENT && offer.extra.assetTransferMethod === "eip3009" && offer.extra.name === "USD Coin" && offer.extra.version === "2" && Number.isInteger(offer.maxTimeoutSeconds) && offer.maxTimeoutSeconds > 0 && offer.maxTimeoutSeconds <= 300 ); } return false; } function selectTrustedOffer( required: PaymentRequired, paymentUrl: string, preferredNetwork: Network, ): TrustedOffer { if (required.x402Version !== 2) throw new Error("Expected x402 v2"); if (required.resource?.url !== paymentUrl) { throw new Error("Challenge resource differs from the saved payment URL"); } const amounts = new Set( required.accepts.map((offer) => positiveAmount(offer.amount).toString()), ); if (amounts.size !== 1) throw new Error("Offered rails disagree on amount"); const offer = required.accepts .filter(isTrustedOffer) .find((candidate) => candidate.network === preferredNetwork); if (!offer) throw new Error("No trusted offer for the selected network"); return offer; } async function previewPayment( paymentUrl: string, preferredNetwork: Network, ): Promise { const response = await fetch(paymentUrl, { method: "POST", redirect: "manual", }); if (response.status !== 402) { throw new Error(`Expected unsigned 402, received ${response.status}`); } const header = response.headers.get("Payment-Required"); if (!header) throw new Error("Payment-Required header is missing"); const paymentRequired = decodePaymentRequiredHeader(header); const selectedOffer = selectTrustedOffer( paymentRequired, paymentUrl, preferredNetwork, ); return { paymentRequiredHeader: header, paymentRequired, selectedOffer, }; } async function saveApproval( store: DurableOrderStore, orderId: string, preview: Preview, wallet: WalletChoice, maximumMicroUsdc: bigint, ): Promise { return store.withExclusiveLock(orderId, async () => { const stored = await store.read(orderId); const state = stored.value; assertOrderIdentity(orderId, state); if (state.paymentSignature || state.transmissionAttemptedAt) { throw new Error("An authorization already exists for this order"); } if (state.stage !== "registered" && state.stage !== "approved") { throw new Error(`Cannot approve an order in stage ${state.stage}`); } const offer = selectTrustedOffer( preview.paymentRequired, state.order.paymentUrl, preview.selectedOffer.network, ); const amount = positiveAmount(offer.amount); if (amount > maximumMicroUsdc) { throw new Error(`Charge ${formatMicroUsdc(amount)} USDC exceeds approval`); } if (wallet.network !== offer.network) { throw new Error("Wallet network differs from the selected offer"); } const approval: Approval = { orderId: state.order.orderId, planId: state.order.planId, months: state.order.months, resourceUrl: state.order.paymentUrl, scheme: "exact", network: offer.network, asset: canonicalIdentifier(offer.network, offer.asset), recipient: canonicalIdentifier(offer.network, offer.payTo), amountMicroUsdc: amount.toString(), expectedPayer: canonicalIdentifier( offer.network, wallet.signer.address, ), approvedAt: new Date().toISOString(), }; const committed = await store.compareAndSwap(orderId, stored.revision, { ...state, stage: "approved", paymentRequiredHeader: preview.paymentRequiredHeader, paymentRequired: preview.paymentRequired, selectedOffer: offer, approval, }); return committed.value; }); } ``` Show the user or calling policy the exact order, plan, months, `wallet.signer.address`, rail, asset, recipient, and `formatMicroUsdc(amount)` before calling `saveApproval`. The maximum is an independent client policy, not a hardcoded plan-price table. A payment URL may remain usable for roughly 24 hours, but an authorization does not. Base authorizations currently use a short expiry window (typically 300 seconds), while Solana validity also depends on a recent blockhash. Create the authorization immediately before transmission. ## Create and save one authorization The lock is acquired and current state is reread before the signer runs. If an authorization already exists, the function returns it without signing again. The official 2.11.0 client awaits `onAfterPaymentCreation`, so the payload and exact encoded header are durable before `createPaymentPayload` returns. ```ts function offerMatchesApproval( offer: PaymentRequirements, approval: Approval, ): boolean { if (!isTrustedOffer(offer) || offer.network !== approval.network) return false; return ( offer.scheme === approval.scheme && canonicalIdentifier(approval.network, offer.asset) === approval.asset && canonicalIdentifier(approval.network, offer.payTo) === approval.recipient && positiveAmount(offer.amount).toString() === approval.amountMicroUsdc ); } async function createSavedAuthorization( store: DurableOrderStore, orderId: string, wallet: WalletChoice, ): Promise { return store.withExclusiveLock(orderId, async () => { const stored = await store.read(orderId); const state = stored.value; assertOrderIdentity(orderId, state); if (state.paymentSignature) return state; if ( state.stage !== "approved" || !state.paymentRequired || !state.selectedOffer || !state.approval ) { throw new Error("Order does not have a durable approved offer"); } const approval = state.approval; const paymentRequired = state.paymentRequired; if ( approval.orderId !== state.order.orderId || approval.planId !== state.order.planId || approval.months !== state.order.months || approval.resourceUrl !== state.order.paymentUrl ) { throw new Error("Approved terms differ from the saved order"); } if (wallet.network !== approval.network) { throw new Error("Wallet network differs from the approved network"); } if ( canonicalIdentifier(wallet.network, wallet.signer.address) !== approval.expectedPayer ) { throw new Error("Wallet payer differs from the approved payer"); } const client = new x402Client((_version, offers) => { const selected = offers.find((offer) => offerMatchesApproval(offer, approval), ); if (!selected) throw new Error("Approved offer is no longer selectable"); return selected; }); if (wallet.network === BASE) { client.register(BASE, new ExactEvmScheme(wallet.signer)); } else { client.register(SOLANA, new ExactSvmScheme(wallet.signer)); } let saved: OrderState | undefined; client.onAfterPaymentCreation(async ({ paymentPayload }) => { const committed = await store.compareAndSwap(orderId, stored.revision, { ...state, stage: "authorized", paymentPayload, paymentSignature: encodePaymentSignatureHeader(paymentPayload), }); saved = committed.value; }); await client.createPaymentPayload(paymentRequired); if (!saved?.paymentSignature) { throw new Error("Authorization was not durably saved"); } return saved; }); } ``` If an unattempted saved authorization expires, prove from durable state that transmission was never marked attempted before clearing it under the same lock, then preview and approve again. Never clear or replace an authorization after `transmissionAttemptedAt` exists or the outcome is ambiguous. ## Transmit once, persist first, then validate The attempted marker is committed before the network write. Once `fetch` resolves, status, **all** headers, the raw receipt, and both grant headers are committed before reading the body. The body is diagnostic only; it is not proof of settlement. ```ts function validateReceipt(state: OrderState): SettleResponse { const raw = state.paidResponse?.paymentResponse; const approval = state.approval; if (!raw || !approval) throw new Error("Settlement receipt is missing"); const receipt = decodePaymentResponseHeader(raw); if (receipt.success !== true) throw new Error("Settlement did not succeed"); if (typeof receipt.network !== "string" || receipt.network !== approval.network) { throw new Error("Settlement network differs from approval"); } if (typeof receipt.payer !== "string" || !receipt.payer.trim()) { throw new Error("Settlement payer is missing"); } if (typeof receipt.transaction !== "string" || !receipt.transaction.trim()) { throw new Error("Settlement transaction is missing"); } if ( canonicalIdentifier(approval.network, receipt.payer) !== approval.expectedPayer ) { throw new Error("Settlement payer differs from approval"); } if ( receipt.amount !== undefined && positiveAmount(receipt.amount).toString() !== approval.amountMicroUsdc ) { throw new Error("Settlement amount differs from approval"); } return receipt; } function validateSavedGrant(state: OrderState): SettleResponse { const receipt = validateReceipt(state); if ( state.paidResponse?.status !== 200 || !state.paidResponse.grantToken || !state.paidResponse.grantSignature ) { throw new Error("Successful receipt or Ambient grant is incomplete"); } return receipt; } async function recoverSavedGrant( store: DurableOrderStore, orderId: string, ): Promise { return store.withExclusiveLock(orderId, async () => { const stored = await store.read(orderId); const state = stored.value; assertOrderIdentity(orderId, state); if (state.stage === "granted" || state.stage === "completed") return state; if (state.stage !== "attempted" || !state.paidResponse) { throw new Error("Order has no recoverable saved paid response"); } const receipt = validateSavedGrant(state); const committed = await store.compareAndSwap(orderId, stored.revision, { ...state, stage: "granted", settlementReceipt: receipt, }); return committed.value; }); } async function transmitSavedAuthorization( store: DurableOrderStore, orderId: string, ): Promise { return store.withExclusiveLock(orderId, async () => { let stored = await store.read(orderId); let state = stored.value; assertOrderIdentity(orderId, state); if (state.stage === "granted" || state.stage === "completed") return state; if (state.stage !== "authorized" || !state.paymentSignature) { throw new Error(`Refusing transmission from stage ${state.stage}`); } const paymentSignature = state.paymentSignature; stored = await store.compareAndSwap(orderId, stored.revision, { ...state, stage: "attempted", transmissionAttemptedAt: new Date().toISOString(), }); state = stored.value; let response: Response; try { response = await fetch(state.order.paymentUrl, { method: "POST", redirect: "manual", headers: { "Payment-Signature": paymentSignature }, signal: AbortSignal.timeout(125_000), }); } catch { const ambiguous = await store.compareAndSwap(orderId, stored.revision, { ...state, stage: "ambiguous", ambiguityReason: "Paid request ended without an HTTP response", }); return ambiguous.value; } const paymentResponse = response.headers.get("Payment-Response") ?? response.headers.get("X-Payment-Response") ?? undefined; const snapshot: PaidResponse = { status: response.status, headers: Object.fromEntries(response.headers.entries()), paymentResponse, grantToken: response.headers.get("X-Ambient-X402-Grant") ?? undefined, grantSignature: response.headers.get("X-Ambient-X402-Grant-Signature") ?? undefined, }; stored = await store.compareAndSwap(orderId, stored.revision, { ...state, paidResponse: snapshot, }); state = stored.value; try { const body = await response.text(); stored = await store.compareAndSwap(orderId, stored.revision, { ...state, paidResponse: { ...snapshot, body }, }); state = stored.value; } catch { // The receipt and grants are already durable; the body is non-authoritative. } try { const receipt = validateSavedGrant(state); const granted = await store.compareAndSwap(orderId, stored.revision, { ...state, stage: "granted", settlementReceipt: receipt, }); return granted.value; } catch (error) { const ambiguous = await store.compareAndSwap(orderId, stored.revision, { ...state, stage: "ambiguous", ambiguityReason: error instanceof Error ? error.message : "Invalid paid response", }); return ambiguous.value; } }); } ``` Jumpgate performs bounded, byte-identical facilitator retries internally: currently at most three facilitator attempts within the 100-second settlement budget, with 250 ms and one-second backoffs. After settlement, its Ambient callback currently makes at most three three-second attempts with the same backoffs. The client still sends the saved paid request once and always calls completion when it has a grant. Treat `409`, `X-Ambient-X402-Error-Code: AMBIGUOUS_X402_SETTLEMENT`, or any non-success after authorization transmission as nonretryable payment state; do not create a replacement authorization or follow generic `Retry-After` behavior. The example intentionally leaves every such result in its terminal local `ambiguous` state even when Jumpgate provides a narrower operational classification. The bounded Jumpgate non-success classifications are: | `phase` | `reason` | `payment_status` | | --- | --- | --- | | `settlement` | `facilitator_rejected` | `facilitator_reported_failure` | | `settlement` | `settlement_unavailable` | `not_submitted` | | `settlement` | `settlement_unconfirmed` | `unknown` | | `receipt_validation` | `missing_receipt`, `missing_network`, `missing_payer`, `missing_transaction`, or `unsupported_network` | `facilitator_reported_success` | | `post_settlement` | `post_settlement_failure` | `facilitator_reported_success` | For `facilitator_rejected`, the optional `facilitator_reason` is one of `insufficient_funds`, `authorization_not_yet_valid`, `authorization_expired`, `invalid_authorization`, `payment_mismatch`, `transaction_rejected`, `unsupported`, or `invalid_response`. It represents a recognized pre-broadcast validation rejection with no settlement identifier. A missing, unrecognized, or conflicting reason, or a failure carrying a transaction or legacy signature, is instead `settlement_unconfirmed` with `payment_status=unknown`. Bounded rejection fields are safe to display but are not independent on-chain proof. `settlement_unavailable` means Jumpgate proved a local failure happened before facilitator submission. The shared `AMBIGUOUS_X402_SETTLEMENT` code is a compatibility envelope: every variant stops automatic retries, but only `payment_status=unknown` or `payment_status=facilitator_reported_success` indicates funds may be at risk. Neither a recognized rejection nor confirmed non-submission permits automatic replacement; the client must preserve its saved authorization and stop payment handling. The operator pager is intentionally narrower than client handling: it fires only for an unknown settlement outcome, a reported success that cannot produce a usable grant, or an Ambient callback that is rejected or exhausts its retries. A downstream client disconnect does not page by itself or cancel an already-started callback, and a successful callback provisions the account even if the client never consumes the response. Intermediaries such as Cloudflare can replace Jumpgate's structured body and headers. The conservative rule applies even when those fields are absent. If a process restarts after saving a valid receipt and both grant headers but before changing the stage to `granted`, call `recoverSavedGrant`. It validates and promotes only the already-saved response and performs no network request. ## Complete with the same grant Completion is public and idempotent. Jumpgate may already have completed the order through its callback, so a client's first completion can legitimately return either `already_completed: false` or `true`. Registration or renewal can return `403` while sales are paused; already-issued valid grants remain completable. The helper below retries only the exact same signed grant on transport errors, `408`, `429`, and `5xx`. It never follows redirects. `400`, `409`, and other nonretryable responses stop for reconciliation and must not trigger another payment. ```ts const sleep = (milliseconds: number) => new Promise((resolve) => setTimeout(resolve, milliseconds)); function parseCompletion(value: unknown, order: PaymentOrder): Completion { if (!value || typeof value !== "object") { throw new Error("Completion response is not an object"); } const body = value as Record; if (typeof body.team_id !== "string" || !body.team_id.trim()) { throw new Error("Completion team_id is missing"); } if (body.plan_id !== order.planId || body.months !== order.months) { throw new Error("Completion does not match the saved order"); } if ( typeof body.current_period_end !== "string" || Number.isNaN(Date.parse(body.current_period_end)) ) { throw new Error("Completion current_period_end is invalid"); } if (typeof body.already_completed !== "boolean") { throw new Error("Completion already_completed is invalid"); } return body as Completion; } function retryableCompletionStatus(status: number): boolean { return status === 408 || status === 429 || status >= 500; } async function completeProvisioning( store: DurableOrderStore, orderId: string, ): Promise { return store.withExclusiveLock(orderId, async () => { let stored = await store.read(orderId); const state = stored.value; assertOrderIdentity(orderId, state); if (state.stage === "completed") return state; if ( state.stage !== "granted" || !state.paidResponse?.grantToken || !state.paidResponse.grantSignature ) { throw new Error("Order does not have a saved grant"); } const requestBody = JSON.stringify({ grantToken: state.paidResponse.grantToken, signature: state.paidResponse.grantSignature, }); const backoffs = [0, 250, 1_000] as const; for (let attempt = 0; attempt < backoffs.length; attempt += 1) { if (backoffs[attempt]) await sleep(backoffs[attempt]); let response: Response; try { response = await fetch(COMPLETION_URL, { method: "POST", redirect: "manual", headers: { "Content-Type": "application/json" }, body: requestBody, signal: AbortSignal.timeout(10_000), }); } catch { if (attempt + 1 < backoffs.length) continue; throw new Error("Completion not confirmed; retry this same grant later"); } if (retryableCompletionStatus(response.status)) { if (attempt + 1 < backoffs.length) continue; throw new Error("Completion not confirmed; retry this same grant later"); } if (!response.ok) { throw new Error( `Completion rejected with HTTP ${response.status}; reconcile without paying again`, ); } let completion: Completion; try { completion = parseCompletion(await response.json(), state.order); } catch { if (attempt + 1 < backoffs.length) continue; throw new Error("Completion response invalid; retry this same grant later"); } stored = await store.compareAndSwap(orderId, stored.revision, { ...state, stage: "completed", completion, }); return stored.value; } throw new Error("Unreachable completion state"); }); } ``` ## Restart matrix Always reread the order under its exclusive lock. | Durable stage | Safe action | | --- | --- | | `registered` | Preview the unsigned challenge and record exact approval. No authorization exists. | | `approved` | Create and durably save one authorization immediately before sending. | | `authorized` | Send the exact saved authorization only if its validity can still be proven. If expired and definitely unattempted, clear it under lock and reapprove. | | `attempted` | Never resend. If a valid receipt and both grants are saved, call `recoverSavedGrant`; otherwise reconcile. | | `granted` | Retry completion using the exact saved grant. This cannot add another month. | | `completed` | Use the API key; do not pay again. | | `ambiguous` | Stop payment automation. Probe initial registration activation once or contact support; never create a replacement authorization. | For an initial registration, the saved bootstrap key returning an authenticated expected subscription from `GET https://api.ambient.xyz/billing/usage-summary` can prove the callback activated it. A `401` does not prove the payment failed. The same probe cannot attribute an ambiguous renewal because the account was already active. When reconciliation is necessary, email [support@ambient.xyz](mailto:support@ambient.xyz) with only the order ID, rail, payer, and transaction or EVM authorization nonce. Never send the API key, `Payment-Signature`, grant, private key, or seed phrase. ## Integration checklist - Persist the complete registration response before payment; the API key is shown once and is inactive until completion. - Model renewal without registration-only key, expiry, or completion URL fields. - Validate the exact resource URL, x402 v2, `exact` scheme, allowlisted asset and recipient, equal offered amounts, and Base EIP-3009 domain and timeout bound. - Persist exact approval, expected payer, authorization, and attempted marker in that order. - Persist paid status, headers, raw receipt, and grants before reading or interpreting the body. - Require a successful typed receipt, expected payer/network, optional amount match, and both grant headers. - Send the paid request once; retry only completion with the same signed grant. - Redact every credential and payment artifact from logs and metrics. - Use mocks for routine tests. Any real payment requires separate approval and an explicit maximum spend. ## Related pages - [Headless x402 subscriptions](https://ambient.xyz/docs/build/x402-subscriptions): endpoints, plans, key management, and limitations - [Pay per request with x402](https://ambient.xyz/docs/build/x402): the single-request payment flow --- # The auction program > Ambient's on-chain auction program. JobRequest lifecycle, bundle and auction account states, the second-lowest reverse auction, and how to request a verified inference job via CPI. - Canonical: https://ambient.xyz/docs/build/on-chain --- The auction program is the native SBF program responsible for creating, bundling, auctioning, and verifying the inference requests a user makes. It owns a small set of account states, runs a second-lowest reverse auction, and exposes an interface your own on-chain program can call to request a verified inference job. > [!NOTE] Status: testnet > The Ambient chain is live as a public testnet. Two crates are involved. `ambient-auction-api` holds the account and data structures expected by each instruction of the auction program. `ambient-auction-interface` provides Pinocchio-based typed helpers for calling the program from your own on-chain program via Cross-Program Invocation (CPI). For operations that need extra processing on the input or output of an inference request, a separate oracle program is used; see the [Tool Oracle](https://ambient.xyz/docs/build/tool-oracle). ## Install ambient-auction-api From your project folder: ```bash cargo add ambient-auction-api --git https://github.com/ambient-xyz/auction-api ``` This adds `ambient-auction-api` to your `Cargo.toml`. ## Program states ### `JobRequest` Account created and owned by the auction program to keep state related to a user inference request. ```rust pub struct JobRequest { /// The public key of the bundle this request is participating in pub bundle: Pubkey, /// The maximum price per output token pub max_price_per_output_token: u64, /// The maximum output token this request accepts pub max_output_tokens: u64, /// Context length tier type pub context_length_tier: RequestTier, /// Expiry duration tier type pub expiry_duration_tier: RequestTier, /// The public key of the job requester. pub authority: Pubkey, /// An [IPFS content identifier](https://docs.ipfs.tech/concepts/content-addressing/) of the metadata necessary to complete the job. pub input_hash: Pubkey, pub input_hash_iv: [u8; 16], /// seeds used to derive the request PDA pub seed: [u8; 32], /// bump for the request account pub bump: u64, /// Output tokens generated pub output_token_count: u64, /// Request input tokens pub input_token_count: u64, /// Current lifecycle stage of the job request. /// /// Indicates whether the request is still awaiting inference, /// pending verification, or already completed. pub status: JobRequestStatus, /// Verification-related state for this job request. /// /// Tracks verifier assignments, token ranges, hashes, and progress /// through the verification process. pub verification: VerificationState, /// account used to store the input data for the inference job request pub input_data_account: Option, /// account used to store the output data for the inference job request pub output_data_account: Option, } /// Represents the lifecycle status of a job request. pub enum JobRequestStatus { /// The request has been created and is waiting for inference output. WaitingForOutput = 0, /// The inference output has been generated and is awaiting verification. OutputReceived = 1, /// The output has been verified and the request is completed. OutputVerified = 2, } /// Holds all data required to manage and track verification of a job request. /// /// Includes: /// - Merkle root of the job's output data. /// - Assigned verifiers and their corresponding token ranges. /// - Individual verifier states and verified token counts. /// - Output hash for integrity checks (optionally encrypted). /// - Initialization vectors (IVs) for optional encryption of the output hash /// and Merkle root, using a shared secret between client and ambient. pub struct VerificationState { pub merkle_root: [u8; 32], pub assigned_verifiers: [Pubkey; VERIFIERS_PER_AUCTION], pub assigned_verifiers_token_ranges: [u64; VERIFIERS_PER_AUCTION * 2], pub verifier_states: [JobVerificationState; VERIFIERS_PER_AUCTION], pub verified_tokens: [u64; VERIFIERS_PER_AUCTION], pub output_hash: [u8; 32], /// output hash and merkle root may be encrypted with a shared secret + iv, /// where shared_secret = ambient private key x client public key /// and IV is a random byte array (a nonce in crypto terms) /// /// encryption is used iff `encryption_iv` != [0; 16] pub output_hash_iv: [u8; 16], pub merkle_root_iv: [u8; 16], } ``` A job request moves through three lifecycle stages: `WaitingForOutput` (created, awaiting inference), `OutputReceived` (output generated, awaiting verification), and `OutputVerified` (verified and complete). The `VerificationState` embedded in each request tracks the Merkle root of the output data, the assigned verifiers with their token ranges, and per-verifier progress. There is more on `RequestTier` in the `RequestBundle` section below. ### `RequestBundle` Economically similar requests are bundled together. Request similarity is based on their context length and expiry duration `RequestTier`. Each (context length, expiry duration) pair has an associated "bundle chain": once a bundle is concluded (marked as `BundleStatus::Cancelled` or `BundleStatus::Filled`), a new child bundle with an identical (context length, expiry duration) pair is created from it. ```rust pub struct RequestBundle { /// Current status of the bundle pub status: BundleStatus, /// Context length tier type pub context_length_tier: RequestTier, /// Expiry duration tier type pub expiry_duration_tier: RequestTier, /// The auction for this bundle. pub auction: Option, /// Assigned verifiers for this bundle. pub verifiers: Verifiers, /// The slot after which the auction cannot receive any more bids /// and is considered ended. pub expiry_slot: u64, /// The maximum input tokens each request can have pub max_context_length: u64, /// Total number of requests contained in this bundle. pub requests_len: u64, /// The number of job requests that were successfully verified pub num_verified_requests: u64, /// limit how much time winning bidder can take to submit all jobs pub job_submission_duration: u64, /// Total amount commited by the requesters pub request_committed_amount: u64, /// Total input tokens in the requests pub total_input_tokens: u64, /// Maximum output tokens to be generated for the requests pub maximum_output_tokens: u64, /// Total output tokens generated for the requests pub output_tokens_generated: u64, /// the parent bundle key is bundle is derived from pub parent_bundle_key: Pubkey, /// The child bundle key to be derived from this bundle pub child_bundle_key: Option, /// bump for this bundle account pub bump: u64, /// payer key for the bundle account creation pub payer: Pubkey, /// The clearing price from the concluded auction for this bundle. /// Denotes the payment rate (in lamports) per output token that the /// winning bidder will receive for fulfilling the bundle's requests. pub price_per_output_token: Option, } ``` ### `Auction` A bundle is put up for auction once it is created. The auction follows a **second-lowest reverse auction**: instead of the lowest bid winning, the second-lowest bidder is selected. The winning bidder must execute every inference request in the bundle and submit the results. These outputs are then verified by a set of randomly assigned verifiers, selected proportionally to their network contribution (their LStake amount). ```rust pub struct Auction { /// Context length tier type pub context_length_tier: RequestTier, /// Expiry duration tier type pub expiry_duration_tier: RequestTier, /// Bundle of requests for this auction. pub request_bundle: Pubkey, /// The slot after which the auction cannot receive any more bids /// and is considered ended. pub expiry_slot: u64, /// The maximum input tokens each request can have pub max_context_length: u64, /// The lowest bid price submitted pub lowest_bid_price: Option, /// The second-lowest bid price submitted pub winning_bid_price: Option, /// The public key of the winning bid account pub winning_bid: Pubkey, /// The public key of the lowest priced bid account pub lowest_bid: Pubkey, /// Current status of the auction pub status: AuctionStatus, /// Total number of bids revealed pub bids_revealed: u64, /// Total number of concealed bids placed pub bids_placed: u64, /// Amount to be kept in each bid account as commitment, pub bid_commitment_amount: u64, /// bump for this auction account pub auction_bump: u64, /// The fee payer for creating this account pub payer: Pubkey, } ``` Note the `bids_placed` / `bids_revealed` counters: bids are placed concealed and revealed later, and each bid account holds a commitment amount. ### `BundleRegistry` For each `RequestTier` combination (each "bundle lane") there is a corresponding registry that keeps track of the current latest active bundle, the one accepting requests. ```rust pub struct BundleRegistry { /// Context length tier type pub context_length_tier: RequestTier, /// Expiry duration tier type pub expiry_duration_tier: RequestTier, /// The latest bundle for this tier. pub latest_bundle: Pubkey, pub payer: Pubkey, /// bump used to derive this account pub bump: u64, } ``` ## The auction interface The `ambient-auction-interface` crate provides Pinocchio-based typed helpers to interact with the auction program through CPIs. Its job is to guarantee that your on-chain program always calls the auction program with: - Correct account order - Correct instruction data layout - Correct signer/writable configuration - Correct discriminators ### Install ambient-auction-interface From your project folder: ```bash cargo add ambient-auction-interface --git https://github.com/ambient-xyz/auction-interface ``` ### High-level responsibilities What your **off-chain client** must do: 1. Create a data account (owned by the auction program) 2. Append input bytes to that account (this can also be done inside of a program) What your **on-chain program** must do: 1. Provide the correct typed accounts 2. Call `RequestJob` via CPI using the interface 3. Optionally read the resulting `JobRequest` account End to end, there are three stages in a verified inference request. ### Stage 1: create and initialize the input data account Before your program can call `RequestJob`, you must prepare a data account that contains the job's input bytes. Requirements: - Must be created off-chain using [`solana_system_interface::instruction::create_account_with_seed`](https://docs.rs/solana-system-interface/3.0.0/solana_system_interface/instruction/fn.create_account_with_seed.html) - Must be owned by the auction program - Must allocate enough space for both `Metadata::LEN` and your input data bytes - Must be funded to be rent-exempt Once created, you upload your input bytes using the auction program's `AppendData` instruction (done client-side or through CPIs). Full example client code: ```rust use auction_api::Metadata; use clap::Parser; use rand::distr::Alphanumeric; use rand::Rng; use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::commitment_config::CommitmentConfig; use solana_sdk::pubkey::Pubkey; use solana_sdk::{ message::{v0::Message, VersionedMessage}, signature::{read_keypair_file, Keypair}, signer::Signer as _, transaction::VersionedTransaction, }; use std::{fmt::Display, path::PathBuf}; #[derive(Parser)] struct Args { /// The keypair that will pay for the auction payer_keypair: PathBuf, /// The Solana RPC cluster URL. Defaults to http://localhost:8899 #[arg(short = 'r', long)] cluster_rpc: Option, /// data to be put onchain data_file: PathBuf, } fn strerr(arg: E) -> String { format!("There was an error: {arg}") } async fn create_data_account( client: &RpcClient, payer: &Keypair, data: &[u8], ) -> Result<(), String> { let space = data.len() + Metadata::LEN; let account_lamports = client .get_minimum_balance_for_rent_exemption(space) .await .map_err(strerr)?; let seed: String = rand::rng() .sample_iter(&Alphanumeric) .take(32) // length .map(char::from) .collect(); let data_account = Pubkey::create_with_seed(&payer.pubkey(), &seed, &ambient_auction_client::ID) .map_err(strerr)?; let mut instructions = vec![ solana_system_interface::instruction::create_account_with_seed( &payer.pubkey(), &data_account, &payer.pubkey(), &seed, account_lamports, space as u64, &ambient_auction_client::ID, ), ]; eprintln!("creating new data account"); let mut offset = Metadata::LEN as u64; for (i, data) in data.chunks(1000).enumerate() { offset += i as u64; let ix = ambient_auction_client::sdk::append_data( payer.pubkey(), data, &seed, offset, data_account, None, ); instructions.push(ix); let tx = VersionedTransaction::try_new( VersionedMessage::V0( Message::try_compile( &payer.pubkey(), &instructions, &[], client.get_latest_blockhash().await.map_err(strerr)?, ) .map_err(strerr)?, ), &[&payer], ) .map_err(strerr)?; let sig = match client .send_and_confirm_transaction_with_spinner(&tx) .await .map_err(strerr) { Ok(sig) => sig, Err(e) => { eprintln!("Error submitting append data txn: {e}"); continue; } }; eprintln!("Appended data to account: {data_account} with Signature: {sig}"); instructions.clear(); } Ok(()) } fn main() -> Result<(), String> { let args = Args::parse(); let payer = read_keypair_file(args.payer_keypair).map_err(strerr)?; let rpc = RpcClient::new_with_commitment( args.cluster_rpc, CommitmentConfig::confirmed(), ); let data = std::fs::read(args.data_file).map_err(strerr)?; tokio::runtime::Builder::new_current_thread() .enable_all() .build() .map_err(strerr)? .block_on(create_data_account(&rpc, &payer, &data)) } ``` After running your client: - The data account exists on-chain - It is owned by the auction program - It contains the serialized input data - It is ready to be passed into your on-chain program This must happen before your program can submit a `RequestJob`. ### Stage 2: call `RequestJob` via CPI Inside your program's instruction (e.g. `RequestInstruction`), you use the interface-provided accounts to build the CPI: ```rust let data = &self.data; let accounts = &self.accounts; // Build CPI account metas in the correct order let metas = accounts .ambient_auction_accounts .to_account_metas() .collect::>(); // Build CPI instruction let ix = pinocchio::instruction::Instruction { program_id: &auction_api::ID, data: &data.ambient_request.to_bytes(), accounts: &metas, }; // Provide raw AccountInfo references in the correct order let account_infos: Vec<&AccountInfo> = accounts.ambient_auction_accounts.inner().iter().collect(); // Execute CPI slice_invoke(&ix, &account_infos)?; ``` The interface ensures: - Account ordering is correct - Signer/writable flags are correct - Instruction data is correctly serialized - Discriminators are correct - Bundle accounts are included properly ### Stage 3: inspect the result (optional) After the CPI, your program can inspect the updated `job_request` account: ```rust let job_request_data = accounts .ambient_auction_accounts .inner() .job_request .try_borrow_data()?; let job_request = try_from_bytes::(&job_request_data)?; ``` This is commonly used to: - Extract the bundle key - Save the request key See the `JobRequest` state documentation above for the exact layout. From there, your program or your off-chain client can track the request's `status` through the lifecycle (`WaitingForOutput` → `OutputReceived` → `OutputVerified`), with the output data account and the `VerificationState` populated as the network completes and verifies the job. ### Quick summary Off-chain: - Create the data account - Append input bytes (can also be on-chain) On-chain: - Construct CPI metas via `.to_account_metas()` - Call `slice_invoke()` - Read back the resulting `JobRequest` if needed ## Related pages - [Tool Oracle](https://ambient.xyz/docs/build/tool-oracle): on-chain LLM calls with outputs written back on-chain - [Solana quickstart](https://ambient.xyz/docs/build/solana-quickstart): Ambient's Solana-compatible RPC - [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits): how verification works underneath --- # Tool Oracle > On-chain LLM inference calls. The Tool Oracle lets you make LLM inference calls with on-chain inputs and configuration, regex-filter outputs, and write results back on-chain where your programs can consume them. - Canonical: https://ambient.xyz/docs/build/tool-oracle --- The Ambient Tool Oracle pairs an on-chain program with an off-chain service so you can make multiple LLM inference calls using inputs and configuration provided from an on-chain source. Outputs can be filtered with regex and written back on-chain, where your own programs can consume them. This page covers the Tool Oracle program itself. The crypto ticker CLI is one minimal example client. Use it as a reference or a starting point, not as the boundary of what the oracle can do. The current Tool Oracle program ID is: ```text 721QWDeUzVL77UCzCFHsVGCMBVup8GsAMPaD2YvWvw97 ``` In code, you typically depend on `oracle-program-types`, which exposes this as `oracle_program_types::ID`. Reference implementation: [oracle-crypto-ticker-app](https://github.com/AmbientCrypto/oracle-crypto-ticker-app). ## Request lifecycle A `ToolOracleRequestAccount` progresses through several states: | State | Meaning | | --- | --- | | `Requested` | Request recorded on-chain, waiting for a worker | | `Started { worker, .. }` | A worker has claimed the request | | `Completed { output, .. }` | The oracle has finished and produced output | | `Failed { reason, completed_requests_arr }` | The request encountered an error | `Completed` and `Failed` are terminal. The steps below create a request, follow it to one of those states, and then reclaim the accounts. ## 1. Dependencies To talk to the Tool Oracle from Rust, you'll usually use: - `oracle-program-types`: type-safe accounts, instructions, and enums for the Tool Oracle - `anchor-client`: high-level client for sending instructions - `solana-sdk`, `solana-client`, `solana-account-decoder-client-types`: Solana primitives and RPC/WebSocket clients - An async runtime such as `tokio` The example CLI also uses `clap`, `tracing`, `anyhow`, and `serde_json`, but those are not required to integrate with the Tool Oracle itself. You will need: - A Solana keypair with SOL to pay for rent, fees, and escrow - RPC and (optionally) WebSocket endpoints for your target cluster ## 2. Set up clients First, construct a Solana client that can talk to the Tool Oracle program. Using `anchor-client`: ```rust let cluster = Cluster::Custom(rpc_url, ws_url); let payer = Arc::new(read_keypair_file(payer_path)?); let program_client = anchor_client::Client::new_with_options( cluster, payer.clone(), CommitmentConfig::processed(), ); let program = program_client.program(ID)?; // ID from oracle_program_types ``` You can optionally create a `PubsubClient` if you want to subscribe to account changes instead of polling. ## 3. Craft a request The request the oracle processes is described by `ToolOracleRequestAccount`. It contains: - The initial prompt or tool description (`initial_prompt`) - Limits on how many external inference calls may be made (`max_requests`) - An optional regex filter for the final output (`output_filter`) - The current request state (`state`) ### Input prompt There are two ways to supply the prompt: - `ToolOracleRequestInput::Direct(prompt)`: inline string input, capped at 800 bytes - `ToolOracleRequestInput::Account(pubkey)`: the prompt is read from another account and interpreted as UTF-8 Most simple prompts can use the direct variant: ```rust let initial_prompt = ToolOracleRequestInput::Direct( "Describe the latest price action for SOL in one sentence.".to_string(), ); ``` ### Request account layout You create a `ToolOracleRequestAccount` that encodes your intent: ```rust let request_data = ToolOracleRequestAccount { state: ToolOracleRequestState::Requested, initial_prompt, max_requests: 5, output_filter: Some(r"^[0-9]+(\.[0-9]{2})?$".to_string()), }; ``` The request account itself is a PDA derived from a fixed seed and the payer's pubkey: ```rust let (request_account, _) = Pubkey::find_program_address( &[b"tool-oracle-request", payer.pubkey().as_ref()], &ID, ); ``` > [!WARNING] > Each payer may only have one in-progress Tool Oracle request at a time. If > a request is still in `Requested` or `Started` state, attempting to > allocate a new one for the same payer will fail. ## 4. Escrow and limits Every request holds some lamports in escrow to pay for LLM inference and the off-chain service: - `escrow`: how many lamports you are willing to spend on this request - `max_requests`: how many external inference calls the oracle is allowed to perform on your behalf Both are configured per request, so you can tune cost and behavior on a per-use basis. ```rust let escrow: u64 = 1_000_000; // example let max_requests: u8 = 5; ``` > [!WARNING] > If escrow is depleted below the amount required to perform further > operations, the oracle marks the request as failed. Check the > `ToolOracleRequestState::Failed` variant for the reason and treat the > request as terminal. The escrow is debited from the payer in addition to rent required to keep the accounts alive. ## 5. Submit a request To create the request account and start processing, you send a `CreateRequest` instruction. With `anchor-client`: ```rust let output_account = None; // or Some(pubkey) if you want output in a separate account let sig = program .request() .accounts(program_accounts::CreateRequest { new_account: request_account, signer: payer.pubkey(), system_program: system_program::id(), output_account, }) .args(program_args::CreateRequest { output_account_size: None, request: request_data, escrow, }) .signer(payer.clone()) .options(CommitmentConfig::processed()) .send() .await?; ``` At this point, the request is on-chain, and the off-chain workers can pick it up and start making tool / LLM calls as described by your input. ## 6. Track request state and get the result There are two common ways to get the result. ### A. Polling (simplest) You can poll the request account until it reaches a terminal state: ```rust loop { let acct = program .account::(request_account) .await?; match acct.state { ToolOracleRequestState::Completed { output, .. } => { // handle output (see below) break; } ToolOracleRequestState::Failed { reason, .. } => { // handle error and break break; } _ => { // still in progress; sleep briefly and try again tokio::time::sleep(Duration::from_millis(500)).await; } } } ``` ### B. PubSub subscription Used by the crypto ticker example. A WebSocket subscription lets you react to changes as soon as they land on-chain: ```rust let (mut updates, unsub) = pubsub .account_subscribe(&request_account, Some(config)) .await?; while let Some(acct) = updates.next().await { let decoded: ToolOracleRequestAccount = /* decode account data */; match decoded.state { ToolOracleRequestState::Completed { output, .. } => { // handle output (see below) break; } ToolOracleRequestState::Failed { reason, .. } => { // handle error and break break; } _ => {} } } unsub().await; ``` ### Interpreting the output Once the state is `Completed`, read the `output` field. It is an `AccountOrString` with two variants: | Variant | Where the response lives | | --- | --- | | `AccountOrString::Direct(text)` | Inlined in the request account | | `AccountOrString::Account(pubkey)` | Stored in another account. Fetch it with `program.rpc().get_account(pubkey)` and interpret as UTF-8 | From there, parse or post-process the string as needed (JSON decoding, numeric parsing) and feed it into your own program or off-chain logic. ## 7. Clean up accounts Because only one request may be in-flight per payer, clean up old request accounts once you are done with them. The oracle exposes a `ReclaimAccounts` instruction to close the request (and optional output) account and return the remaining lamports to a destination: ```rust program .request() .accounts(program_accounts::ReclaimAccounts { job_request: request_account, output: output_account, destination: payer.pubkey(), signer: payer.pubkey(), system_program: system_program::id(), }) .args(program_args::ReclaimAccounts { destination: payer.pubkey(), }) .signer(payer.clone()) .send() .await?; ``` > [!NOTE] > If cleanup fails because the account has already been closed or cannot be > deserialized, you'll typically see a warning-level error. Your application > can log it and continue. ## 8. Using the crypto ticker example The CLI in [oracle-crypto-ticker-app](https://github.com/AmbientCrypto/oracle-crypto-ticker-app) ties all of the above together into a single example: it builds a prompt asking for the current USD price of a chosen ticker symbol, submits a Tool Oracle request, waits for completion, and prints the result. Use it as a reference implementation for: - Setting up `anchor-client` and deriving the request PDA - Choosing `escrow`, `max_requests`, and an `output_filter` - Subscribing to account updates to react to state changes in real time - Cleaning up request and output accounts when finished Once you are comfortable with the example, adapt the same pattern to your own contracts and clients: richer prompts, tool-based workflows, or program-controlled follow-up actions driven by the oracle's output. ## Related pages - [The auction program](https://ambient.xyz/docs/build/on-chain): how inference requests are bundled, auctioned, and verified on-chain - [Solana quickstart](https://ambient.xyz/docs/build/solana-quickstart): Ambient's Solana-compatible RPC - [Verified inference](https://ambient.xyz/docs/build/verified-inference): what the network guarantees about the output the oracle writes back --- # Solana quickstart > Connecting Solana tooling to Ambient. The Solana-compatible RPC endpoint, SVM compatibility, and where the JumpGate relayer fits. - Canonical: https://ambient.xyz/docs/build/solana-quickstart --- Ambient's chain is SVM-compatible, so standard Solana SDKs and tools work against it. Point them at the RPC endpoint below; for inference from Solana applications, the current path is x402 through the JumpGate relayer. > [!NOTE] Status: testnet > The Ambient chain is live as a public testnet. ## RPC compatibility Ambient provides a Solana-compatible RPC API. You can connect with all Solana SDKs and tools: ```text https://rpc.ambient.xyz ``` ## SVM compatibility This is the resource page for understanding how to use Ambient's verified inference with Solana. ## The JumpGate relayer JumpGate now supports inference through x402 requests. The legacy vault-backed relayer endpoints are no longer the supported integration path and may return `410 Gone`. For current integration details, see [Pay per request with x402](https://ambient.xyz/docs/build/x402). ## Helpful links - [Solana Docs](https://solana.com/docs) - [Rust SDK](https://solana.com/docs/clients/official/rust) - [JavaScript SDK](https://solana.com/docs/clients/official/javascript) ## Related pages - [The auction program](https://ambient.xyz/docs/build/on-chain): account states and the verified-inference job flow - [Tool Oracle](https://ambient.xyz/docs/build/tool-oracle): on-chain LLM calls - [Pay per request with x402](https://ambient.xyz/docs/build/x402): USDC pay-per-request inference --- # Run a node > How mining works on Ambient today: live, curated onboarding waves for datacenter-class hardware, with a consumer Mini Miner on the roadmap. - Canonical: https://ambient.xyz/docs/mine --- Mining on Ambient is live today, in curated onboarding waves on datacenter-class hardware. A consumer path, the Mini Miner, is planned but not yet available. ## Mining today: curated waves Onboarding is deliberately gated. New miners join in curated waves under an agreement with the Ambient team rather than through permissionless self-serve. Serving the flagship network model takes datacenter-class hardware. What miners do on the network: - Bid on inference queries through the on-chain auction. A bid is a deposit, returned when the query completes within its promised time and forfeited if it does not; earnings come from network rewards, not the deposit. - Run inference on the network model, committing [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits) hashes as they generate. - Validate peers' work when assigned: recompute a small, randomly selected portion of another node's output and confirm its logit hashes. This spot check is cheap relative to the original inference, and validation assignments are weighted by accumulated work credit. - Accumulate work credit (LStake) for validated contributions, which drives rewards and leader election. Invalid work is penalized by retrospective slashing of that work credit. See [Tokenomics](https://ambient.xyz/docs/learn/tokenomics) for the reward design. > [!WARNING] Coming soon > Exact minimum hardware specifications (GPU class, VRAM, networking, > storage) are published per onboarding wave, not on this page. Assume > datacenter-class multi-GPU requirements and confirm specifics during > onboarding. ## Mini Miner: roadmap A consumer-hardware path, the [Mini Miner](https://ambient.xyz/docs/mine/mini-miner), is on the roadmap. Hardware requirements will be published at launch. ## Express interest If you operate datacenter-class GPU capacity and want to join a future wave, register interest at [ambient.xyz/mining](https://ambient.xyz/mining) or email the team directly at [hello@ambient.xyz](mailto:hello@ambient.xyz). ## Keep reading - [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits): the work you are paid for - [Network architecture](https://ambient.xyz/docs/learn/architecture): auction, inference, verification, settlement - [Mini Miner](https://ambient.xyz/docs/mine/mini-miner): the planned consumer-hardware path --- # Mini Miner > The planned, opt-in path for a machine already running local models to serve the Ambient network and earn rewards. Roadmap, nothing to install or buy today. - Canonical: https://ambient.xyz/docs/mine/mini-miner --- The Mini Miner is a planned, opt-in way for a machine that already runs local models through Ambient Desktop to do useful work for the network when you are not using it. It is roadmap: there is nothing to install, configure, or buy for it today. [Diagram: Ambient Mini Mining And Routing diagram. A Mineable machine (opt-in, runtime, rewards) moves through four stages: 1 Opt in (Mineable flag, Resource policy, Privacy boundary) grants consent; 2 Host (llama.cpp, Ambient Mini, Health checks) serves model; 3 Route (Eligibility, Request dispatch, Utilization) routes work; 4 Reward (Receipts, Network rewards, Operator controls) tracks rewards.] *Ambient Mini Mining And Routing: mining is opt-in and depends on local runtime readiness, user policy, and network routing eligibility.* > [!WARNING] Mining today is not this > Live mining on Ambient runs in curated waves on datacenter-class > hardware; see [Run a node](https://ambient.xyz/docs/mine). The Mini Miner is the planned > consumer-scale complement. ## The idea Ambient Desktop already manages local model runtimes for your own tasks (see [Local models and routing](https://ambient.xyz/docs/use/desktop/local-models)). The Mini Miner extends that: with your explicit consent, an eligible machine could serve a local model to the network and earn rewards for the work it does. It is opt-in by design. Nothing mines unless you set a machine-level mineable flag and accept the resource, privacy, and uptime implications. ## How opting in is designed to work ### 1. Opt in Mark a machine as mineable and set a resource policy and privacy boundary. Off by default; you choose when and how much. ### 2. Host Ambient serves a local model through its managed llama.cpp runtime, with health checks verifying the host is serving correctly. ### 3. Route When the machine is eligible, the network routes appropriate requests to it based on availability and policy. ### 4. Reward Completed work produces receipts and network rewards, with operator controls to pause or stop. ## The foundation that exists today The Mini Miner will stand on the runtime layer Ambient Desktop ships today: - llama.cpp hosting with non-destructive start/stop lifecycle management. - Local runtime inventory, health checks, and repair flows. - Provider routing and local-first model selection. - The [network client](https://ambient.xyz/docs/use/desktop/network-client) direction for reward receipts and operator controls. ## Rewards Mini mining promises network rewards and deliberately stops there: no fixed payout, no guaranteed income, and no final token economics. Those depend on the public network contract, which is not finalized. See [tokenomics](https://ambient.xyz/docs/learn/tokenomics) for the reward design as it stands. ## Keep reading - [Run a node](https://ambient.xyz/docs/mine): what mining on Ambient looks like today - [Local models and routing](https://ambient.xyz/docs/use/desktop/local-models): the runtime foundation - [Tokenomics](https://ambient.xyz/docs/learn/tokenomics): the reward design --- # Enterprise > Ambient for organizations: verified inference for auditability, data retention and privacy, and how to start a deployment conversation. - Canonical: https://ambient.xyz/docs/enterprise --- Ambient offers organizations auditable inference behind a drop-in gateway. ## Why enterprises look at Ambient - **Provenance you can audit.** [Proof of Logits](https://ambient.xyz/docs/learn/proof-of-logits) is designed to prove which model produced which output. Verification establishes execution integrity; it does not certify that an answer is factually true. - **A drop-in gateway.** The API at `api.ambient.xyz` is OpenAI- and Anthropic-compatible, so adopting it is a base-URL swap behind your existing SDKs rather than a re-integration. - **No platform-competition risk.** An open network can't unilaterally change model behavior on you or compete with the product you built on it. ## Security and compliance posture Ambient's infrastructure is architected for SOC 2 Type II controls. A completed attestation is not yet published; it will be linked here when available. ## Data retention Ambient's design goal is zero data retention by default, including reasoning content. The enforcement mechanics differ by network stage: - **Today (testnet):** the zero-data-retention posture is enforced through whitelisted infrastructure; requests are served only by vetted operators under agreement. - **Planned for mainnet:** protocol-level protections, including onion routing of queries and end-to-end encryption, so the guarantee stops depending on operator vetting. The longer-term privacy design also includes client-side PII obfuscation using a small local model, and query-origin obfuscation through the [query auction](https://ambient.xyz/docs/learn/architecture) itself. **Need zero data retention today?** If your requirements call for a contractual ZDR guarantee before the mainnet protections land, we support direct enterprise deployments on dedicated or on-prem infrastructure that meet ZDR standards now. [Contact us](https://ambient.xyz/enterprise#contact) to scope one. ## Service levels > [!WARNING] Coming soon > SLA terms (uptime targets, support response times, and the contractual > commitments behind them) are set per deployment. Ask for current terms in a > deployment conversation. ## Deployment options and contact Enterprise deployments can include dedicated capacity and custom integrations, scoped case by case. To start a deployment conversation, email [hello@ambient.xyz](mailto:hello@ambient.xyz) or reach the team through [ambient.xyz](https://ambient.xyz). ## Keep reading - [Get started](https://ambient.xyz/docs/get-started): evaluate the API in an afternoon - [Build on Ambient](https://ambient.xyz/docs/build): the full API reference for the OpenAI and Anthropic SDKs, direct HTTP, and the Claude Code and Codex integrations - [What is Ambient?](https://ambient.xyz/docs/learn/what-is-ambient): the network in one page --- # Maturity labels > What Available, Developer Preview, In Development, and Roadmap each promise, and how they map to the maturity value every page in these docs carries. - Canonical: https://ambient.xyz/docs/resources/maturity-labels --- Every page in these docs carries one of four labels. They tell you what to rely on, what to test, and where the implementation is still moving. They are operational signals, not marketing tiers. ## What each label means This is what a label promises, and what it does not. | Label | What it means | How to treat it | | --- | --- | --- | | Available | Documented user path with validation evidence, troubleshooting, and stable UX. | Rely on it for real work. | | Developer Preview | Substantial implementation and tests exist; the team is still proving edge cases. | Use it, expect rough edges, report surprises. | | In Development | Important building blocks exist, but UX, contracts, or validation are still moving. | Experiment; do not depend on stability yet. | | Roadmap | Strategic direction worth seeing, not yet promised as available. | Read for intent; check back for progress. | ## How they map to page metadata Each page on this site declares a `maturity` value in its frontmatter, from a four-value vocabulary. The mapping to the labels above: | Page `maturity` | Product label | | --- | --- | | `live` | Available | | `beta` | Developer Preview, or In Development | | `roadmap` | Roadmap | | `deprecated` | No product-label equivalent, a path that has been superseded | ## The reliability contract Every page prefers exact maturity over vague optimism. If a feature is strategic but not shipped, the page says so plainly and points at the building blocks that do exist. That is the deal: you should never have to guess whether something on this site is real today or aspirational. > [!NOTE] Reliability contract > Every feature page separates available behavior, developer-preview > behavior, active development, and roadmap direction. Source paths, > validation commands, and known limits are part of that contract. ## Keep going - [Product north star](https://ambient.xyz/docs/use/desktop/north-star): the candid product thesis. Ambient Desktop becomes the workstation for agentic work on the Ambient Network. - [Quickstart](https://ambient.xyz/docs/use/desktop/quickstart): start in the Welcome Folder, finish setup, then run a small calculator task with visible proof. - [Project board](https://ambient.xyz/docs/use/desktop/project-board): turns goals into durable plans, task cards, source-backed evidence, and review loops. --- # Changelog > Dated changes to the Ambient network and this documentation. - Canonical: https://ambient.xyz/docs/resources/changelog --- Dated changes to the Ambient network and to this documentation, newest first. ## 2026-07-02 - Documentation relaunched: unified structure, grouped navigation, generated model catalog and API reference, per-page Markdown export.