PageSourceSearch

https://cognitum.one/assets/SdkRustPage-Z7HHkonX.js

js cognitum.one collected 2026-09-25 14:20:43 UTC 53,985 bytes, 670 lines download raw bytes

1import{j as e}from"./vendor-CR4GEDXU.js";import{H as m,L as n}from"./index-DEH-EspT.js";import{f as o}from"./firmware-versions.generated-DU3mt0lW.js";import{N as p}from"./Navbar-tOzc1LfG.js";import{F as h}from"./Footer-D5psJso-.js";import{S as x,b as g}from"./sdkNav-BqoeXEOd.js";import{T as t}from"./TabsBar-De5UaXKx.js";import{A as f}from"./AgenticSdkSection-DGmhWeZG.js";import{R as b}from"./ReleaseValidationNotice-B_ENU5zk.js";import{P as l}from"./package-uxgXzK9w.js";import{E as c}from"./external-link-KY1DdKsQ.js";import"./ui-C4oFTs1l.js";import"./query-DOtdOdQ4.js";import"./input-DokEs6ju.js";import"./CogDetailModal-DG7TMr0D.js";import"./lock-DvwRkkXo.js";import"./cognitum-logo-nav-Ab5-TKQ3.js";import"./search-DqP_1Y0P.js";import"./chevron-right-BX5NHfjR.js";import"./check-CqweXUBF.js";import"./code-C6nbiYvx.js";import"./sparkles-_bU26kwM.js";import"./gauge-CagVqRJN.js";import"./loader-circle-DzNOjQOo.js";import"./bot-CmTw7lot.js";import"./arrow-right-DHxjqloZ.js";import"./boxes-DrYmbB5j.js";import"./book-open-6GoY8iOl.js";import"./file-text-BT0Z1DR3.js";import"./users-BsIOobnr.js";import"./store-Bt_NW7kz.js";import"./mail-D8JM50xB.js";import"./menu-BVmwL0l-.js";import"./form-ByOlb__1.js";import"./label-BVgsVZnH.js";import"./ContactForm-DepiRU5V.js";import"./user-4wq7CL7j.js";import"./send-fpPRiXLF.js";import"./copy-BYO_mxRP.js";import"./shield-check-huqoaCnu.js";import"./triangle-alert-X0cjaitZ.js";import"./circle-check-CxnIeXQm.js";const r=o.cognitumSdkRust.replace(/^v/,""),y=[{id:"status",label:"Status"},{id:"install",label:"Install"},{id:"config",label:"Configuration"},{id:"quickstart",label:"Quickstart"},{id:"agentic-platform",label:"Agentic platform · v0.3"},{id:"cloud-catalog",label:"Cloud · Catalog"},{id:"cloud-orders",label:"Cloud · Orders"},{id:"cloud-leads-contact",label:"Cloud · Leads / Contact"},{id:"cloud-devices",label:"Cloud · Devices / OTA"},{id:"cloud-mcp",label:"Cloud · MCP"},{id:"cloud-brain",label:"Cloud · Brain"},{id:"seed-connect",label:"Seed · Connect"},{id:"seed-call-options",label:"Seed · Per-call options"},{id:"seed-tls",label:"Seed · TLS"},{id:"seed-pair",label:"Seed · Pair"},{id:"seed-status",label:"Seed · Status / Identity"},{id:"seed-store",label:"Seed · Store"},{id:"seed-witness",label:"Seed · Witness / Custody"},{id:"seed-ota",label:"Seed · OTA"},{id:"seed-mesh",label:"Seed · Mesh"},{id:"discovery",label:"Discovery"},{id:"tokens",label:"Tokens"},{id:"errors",label:"Errors"},{id:"features",label:"Cargo features"},{id:"related",label:"Related"}];function le(){const d={"@context":"https://schema.org","@type":"TechArticle",headline:"Cognitum Rust SDK",description:`Async Rust SDK source/package snapshot ${o.cognitumSdkRust}. Cloud and Seed clients plus feature-gated agentic integrations; staging validation pending.`,url:"https://cognitum.one/sdks/rust"};return e.jsxs(e.Fragment,{children:[e.jsxs(m,{children:[e.jsx("title",{children:"Rust SDK · cognitum-one | Cognitum"}),e.jsx("meta",{name:"description",content:"cognitum-one Rust SDK source contract. Async cloud and feature-gated Seed/agentic clients; registry snapshot and staging status are called out separately."}),e.jsx("link",{rel:"canonical",href:"https://cognitum.one/sdks/rust"}),e.jsx("meta",{property:"og:type",content:"website"}),e.jsx("meta",{property:"og:url",content:"https://cognitum.one/sdks/rust"}),e.jsx("meta",{property:"og:title",content:"cognitum-one · Rust SDK"}),e.jsx("meta",{property:"og:description",content:"Async (tokio) Rust SDK for Cognitum. Cloud catalog/orders/MCP/brain/devices, mesh routing, TLS pinning, mDNS / Tailscale discovery."}),e.jsx("meta",{name:"twitter:title",content:"cognitum-one · Rust SDK"}),e.jsx("meta",{name:"twitter:description",content:"cargo add cognitum-one — async Rust client for the Cognitum platform."}),e.jsx("script",{type:"application/ld+json",children:JSON.stringify(d)})]}),e.jsxs("div",{className:"min-h-screen bg-background",children:[e.jsx(p,{}),e.jsx("main",{role:"main","aria-label":"Rust SDK",children:e.jsx("div",{className:"pt-28 pb-20",children:e.jsx(x,{title:"Rust SDK",sdkNav:g("rust"),pageNav:y,children:e.jsxs("div",{className:"space-y-10",children:[e.jsxs("header",{children:[e.jsxs("div",{className:"flex items-center gap-2 text-xs text-muted-foreground mb-2",children:[e.jsx(l,{className:"h-3.5 w-3.5"}),e.jsx("code",{className:"font-mono",children:"cognitum-one"}),e.jsxs("span",{className:"text-[10px] font-medium px-2 py-0.5 rounded-full bg-amber-500/10 text-amber-400 border border-amber-500/20",children:["Registry snapshot · ",o.cognitumSdkRust]})]}),e.jsx("h1",{className:"text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-2",children:"Rust SDK"}),e.jsxs("p",{className:"text-base text-muted-foreground max-w-2xl",children:["Async Rust client (tokio) for Cognitum. Talk to the ",e.jsx("strong",{children:"Cognitum Cloud"})," control plane (catalog, orders, leads, contact, devices/OTA, MCP, brain) with the default build, or enable the"," ",e.jsx("code",{className:"font-mono text-xs",children:"seed"})," feature to talk directly to a ",e.jsx("strong",{children:"Seed"})," ","appliance — mesh routing, TLS pinning, mDNS / Tailscale discovery, redaction-safe pairing tokens, per-call routing knobs. Ships an MCP client with both HTTP and stdio transports."]})]}),e.jsx(b,{localEvidence:`The local Cargo metadata identifies cognitum-one ${o.cognitumSdkRust}, and its source/tests define the direct Seed and feature-gated agentic namespaces shown here.`,pendingEvidence:"The root cloud client still calls legacy raw-function paths such as /health and /listTemplates instead of the canonical /v1 routes. Do not treat its cloud examples as release-ready until route alignment and staging E2E pass.",title:"Rust SDK compatibility"}),e.jsxs("section",{children:[e.jsx("h2",{id:"status",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Status"}),e.jsx("div",{className:"border border-amber-500/30 bg-amber-500/5 rounded-xl p-4 text-sm text-amber-100/90",children:e.jsxs("p",{children:[e.jsxs("strong",{children:[e.jsx("code",{className:"font-mono",children:"cognitum-one"})," ",o.cognitumSdkRust," is the local source/package version."]})," ","The generated registry snapshot records the same version, but this pre-deploy review did not perform a live registry install or staging cloud-client journey."]})})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"install",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Install"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["Cloud-only is the default; the seed surface is gated behind the ",e.jsx("code",{className:"font-mono text-xs",children:"seed"})," ","feature so cloud users don't pay the URL parser / rustls-pinning weight."]}),e.jsx(t,{tabs:[{label:"cargo add",lang:"bash",code:`# Cloud only (catalog, orders, MCP, brain, devices, leads, contact)
2cargo add cognitum-one
3
4# + direct-to-seed surface
5cargo add cognitum-one --features seed
6
7# + mDNS discovery for LAN seeds
8cargo add cognitum-one --features seed,mdns`},{label:"Cargo.toml",lang:"toml",code:`[dependencies]
9# Cloud only
10cognitum-one = "${r}"
11
12# Seed surface
13cognitum-one = { version = "${r}", features = ["seed"] }
14
15# Seed + mDNS discovery
16cognitum-one = { version = "${r}", features = ["seed", "mdns"] }
17
18# Cloud + blocking client (no tokio runtime needed)
19cognitum-one = { version = "${r}", features = ["blocking"] }
20
21# Use native-tls instead of the default rustls
22cognitum-one = { version = "${r}", default-features = false, features = ["native-tls"] }`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"config",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Configuration (Cloud)"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["The cloud ",e.jsx("code",{className:"font-mono text-xs",children:"Client"})," is constructed from a"," ",e.jsx("code",{className:"font-mono text-xs",children:"ClientConfig"})," or via the fluent"," ",e.jsx("code",{className:"font-mono text-xs",children:"ClientBuilder"}),". Authentication is"," ",e.jsx("code",{className:"font-mono text-xs",children:"X-API-Key"})," per ADR-0003; a deprecated"," ",e.jsx("code",{className:"font-mono text-xs",children:"Authorization: Bearer"})," can be enabled for one deprecation window."]}),e.jsx(t,{tabs:[{label:"Builder",lang:"rust",code:`use cognitum_one::Client;
23
24let client = Client::builder()
25    .api_key(std::env::var("COGNITUM_API_KEY")?)
26    .base_url("https://api.cognitum.one")    // default
27    .timeout_secs(30)                         // default 30s per attempt
28    .max_retries(3)                           // default 3 (ADR-0005)
29    .build()?;
30
31let health = client.health().await?;
32println!("api status: {}", health.status);`},{label:"ClientConfig",lang:"rust",code:`use cognitum_one::{Client, ClientConfig};
33
34// Full struct shape — every field except api_key has a default.
35let config = ClientConfig {
36    api_key: std::env::var("COGNITUM_API_KEY")?,
37    base_url: None,            // -> https://api.cognitum.one
38    timeout_secs: 30,
39    max_retries: 3,
40    use_bearer: false,         // ADR-0003 deprecation flag
41    insecure: false,           // dev-only: accept self-signed
42    trust_root_pem: None,      // pin a custom root CA (mutually exclusive with insecure)
43};
44
45let client = Client::try_with_config(config)?;`},{label:"Self-signed CA",lang:"rust",code:`// Pin a single root CA — system trust store is disabled.
46// For self-signed staging or on-prem deployments.
47let client = Client::builder()
48    .api_key(std::env::var("COGNITUM_API_KEY")?)
49    .trust_root_pem_file("./cognitum-ca.pem")?
50    .build()?;`},{label:"Insecure (dev only)",lang:"rust",code:`// Skips cert verification entirely. Emits a one-shot stderr warning.
51// Mutually exclusive with .trust_root_pem(_file) — build() returns
52// Error::Validation if both are set.
53let client = Client::builder()
54    .api_key("dev-key")
55    .danger_accept_invalid_certs(true)
56    .build()?;`},{label:"Bearer (deprecated)",lang:"rust",code:`// Sends \`Authorization: Bearer\` in addition to X-API-Key,
57// for compatibility with pre-ADR-0003 servers. Will be removed
58// in 2 minor releases. Set COGNITUM_SUPPRESS_BEARER_WARNING=1
59// to silence the stderr deprecation notice.
60let client = Client::builder()
61    .api_key(std::env::var("COGNITUM_API_KEY")?)
62    .deprecated_bearer_auth(true)
63    .build()?;`}]}),e.jsxs("p",{className:"text-[12px] text-muted-foreground mt-3",children:["The retry loop honours ",e.jsx("code",{className:"font-mono text-xs",children:"Retry-After"})," on 429s (header seconds, HTTP-date, body ",e.jsx("code",{className:"font-mono text-xs",children:"retry_after_us"}),', or "retry after Ns" text), and falls back to ADR-0005 equal-jitter backoff for 500 / 503. Body signal wins over header so proxies that strip ',e.jsx("code",{className:"font-mono text-xs",children:"Retry-After"})," still surface a sane delay."]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"quickstart",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Quickstart"}),e.jsx(t,{tabs:[{label:"Cloud",lang:"rust",code:`use cognitum_one::{Client, Error};
64
65#[tokio::main]
66async fn main() -> Result<(), Error> {
67    let client = Client::new(&std::env::var("COGNITUM_API_KEY").unwrap());
68
69    let catalog = client.catalog().browse().await?;
70    println!("{} products", catalog.products.len());
71    Ok(())
72}`},{label:"Seed (direct)",lang:"rust",code:`use cognitum_one::seed::{SeedClient, SeedTls};
73
74#[tokio::main]
75async fn main() -> Result<(), cognitum_one::Error> {
76    let client = SeedClient::builder()
77        .endpoint("https://cognitum.local:8443")
78        .tls(SeedTls::Insecure)        // dev-only — see "Seed · TLS"
79        .build()?;
80
81    let status = client.status().await?;
82    println!("seed {} epoch {} ({} vectors)",
83             status.device_id, status.epoch, status.total_vectors);
84    Ok(())
85}`},{label:"curl",lang:"bash",code:`# Cloud
86curl https://api.cognitum.one/v1/catalog
87curl -H "X-API-Key: $COGNITUM_API_KEY" \\
88     -H "Content-Type: application/json" \\
89     -X POST https://api.cognitum.one/v1/payment \\
90     -d '{"email":"[email protected]","quantity":1}'
91
92# Seed (direct, allowlisted reads)
93curl -k https://cognitum.local:8443/api/v1/status
94curl -k https://cognitum.local:8443/api/v1/store/status`}]})]}),e.jsx(f,{language:"rust"}),e.jsxs("section",{children:[e.jsx("h2",{id:"cloud-catalog",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Cloud · Catalog"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["Hangs off ",e.jsx("code",{className:"font-mono text-xs",children:"client.catalog()"})," →"," ",e.jsx("code",{className:"font-mono text-xs",children:"CatalogResource"}),". Returns a"," ",e.jsx("code",{className:"font-mono text-xs",children:"CatalogResponse"})," with a typed"," ",e.jsx("code",{className:"font-mono text-xs",children:"Vec<Product>"}),"."]}),e.jsx(t,{tabs:[{label:"Browse",lang:"rust",code:`let catalog = client.catalog().browse().await?;
95for p in &catalog.products {
96    let cents = p.price_cents.unwrap_or(0);
97    println!("{:24}  \${}.{:02}", p.name, cents / 100, cents % 100);
98}
99
100// Filter by category — encodes the value with a minimal percent-encoder.
101let hardware = client.catalog().browse_with_category("hardware").await?;`},{label:"Product type",lang:"rust",code:`pub struct Product {
102    pub id: String,
103    pub name: String,
104    pub description: Option<String>,
105    pub category: Option<String>,
106    pub price_cents: Option<u64>,
107    pub image_url: Option<String>,
108    pub available: Option<bool>,
109}`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"cloud-orders",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Cloud · Orders"}),e.jsx(t,{tabs:[{label:"Create + status",lang:"rust",code:`// Create a presale payment intent.
110let created = client.orders()
111    .create("[email protected]", 1)
112    .await?;
113println!("client_secret = {}", created.client_secret);
114if let Some(id) = created.order_id {
115    println!("order id = {id}");
116}
117
118// Look up existing orders by email — returns Vec<Order>.
119let orders = client.orders().status("[email protected]").await?;
120for o in orders {
121    println!("{:>10}  {:8}  {}", o.order_id, o.status, o.email);
122}`},{label:"Types",lang:"rust",code:`pub struct Order {
123    pub order_id: String,
124    pub email: String,
125    pub status: String,
126    pub quantity: Option<u32>,
127    pub amount_cents: Option<u64>,
128    pub created_at: Option<String>,
129}
130
131pub struct OrderCreateResponse {
132    pub client_secret: String,
133    pub order_id: Option<String>,
134}`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"cloud-leads-contact",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Cloud · Leads / Contact"}),e.jsx(t,{tabs:[{label:"Leads",lang:"rust",code:`// Subscribe an email to the notify-me / waitlist for a product.
135let resp = client.leads()
136    .subscribe("[email protected]", "seed-v1")
137    .await?;
138assert!(resp.success);`},{label:"Contact",lang:"rust",code:`let resp = client.contact()
139    .send(
140        "Dev",                       // name
141        "[email protected]",          // email
142        "Hi — question about ordering.", // message
143        "general",                   // inquiry_type ("general", "sales", "support", ...)
144    )
145    .await?;
146assert!(resp.success);`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"cloud-devices",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Cloud · Devices / OTA"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["Three operations on ",e.jsx("code",{className:"font-mono text-xs",children:"client.devices()"}),":"," ",e.jsx("code",{className:"font-mono text-xs",children:"register"}),", ",e.jsx("code",{className:"font-mono text-xs",children:"check_update"}),","," ",e.jsx("code",{className:"font-mono text-xs",children:"heartbeat"}),"."]}),e.jsx(t,{tabs:[{label:"Register",lang:"rust",code:`// Register a new device with its Ed25519 public key.
147let device = client.devices()
148    .register("ed25519:f00ba4...")
149    .await?;
150println!("device {}", device.device_id);`},{label:"Check update",lang:"rust",code:`let r = client.devices()
151    .check_update("seed-001", "0.20.1")
152    .await?;
153if r.update_available {
154    println!("update available: {:?}", r.version);
155    if let Some(url) = r.download_url {
156        println!("download: {url}");
157    }
158}`},{label:"Heartbeat",lang:"rust",code:`// Periodic liveness ping; updates last-seen timestamp.
159let r = client.devices().heartbeat("seed-001").await?;
160assert!(r.success);`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"cloud-mcp",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Cloud · MCP"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["Two distinct surfaces ship under ",e.jsx("code",{className:"font-mono text-xs",children:"cognitum_one::mcp"}),":"," ",e.jsx("code",{className:"font-mono text-xs",children:"McpResource"})," (cloud HTTP proxy hanging off"," ",e.jsx("code",{className:"font-mono text-xs",children:"client.mcp()"}),") and the protocol-level"," ",e.jsx("code",{className:"font-mono text-xs",children:"McpClient"})," parameterised over a"," ",e.jsx("code",{className:"font-mono text-xs",children:"Transport"})," with concrete"," ",e.jsx("code",{className:"font-mono text-xs",children:"HttpTransport"})," and ",e.jsx("code",{className:"font-mono text-xs",children:"StdioTransport"}),"."]}),e.jsx(t,{tabs:[{label:"Cloud proxy",lang:"rust",code:`use serde_json::json;
161
162// List + call against the cloud MCP endpoint.
163let tools = client.mcp().list_tools().await?;
164println!("{} tools", tools.len());
165
166let result = client.mcp()
167    .call_tool("catalog_browse", json!({ "category": "hardware" }))
168    .await?;
169
170// Search docs index.
171let hits = client.mcp().search_docs("authentication patterns", Some(5)).await?;
172for h in hits {
173    println!("{}: {}", h.title, h.snippet.unwrap_or_default());
174}
175
176// Initialize handshake (returns server protocolVersion / capabilities).
177let init = client.mcp().initialize().await?;`},{label:"Protocol-level (HTTP)",lang:"rust",code:`use cognitum_one::mcp::{HttpTransport, McpClient};
178use serde_json::json;
179
180let transport = HttpTransport::new(
181    "https://api.cognitum.one/v1/mcp/sse",
182    &std::env::var("COGNITUM_API_KEY")?,
183)?;
184let mut mcp = McpClient::new(transport);
185
186mcp.initialize().await?;
187let tools = mcp.list_tools().await?;
188let out = mcp.call_tool("health_check", json!({})).await?;
189println!("{out}");
190mcp.close().await?;`},{label:"Protocol-level (stdio)",lang:"rust",code:`use cognitum_one::mcp::{McpClient, StdioTransport};
191use serde_json::json;
192
193// Spawn a local MCP server subprocess (any newline-delimited
194// JSON-RPC server). Stderr is drained to a background tokio task
195// so the child can never wedge the pipe.
196let transport = StdioTransport::builder()
197    .command("npx")
198    .args(["-y", "@some/mcp-server"])
199    .env("SOME_KEY", "secret")
200    .spawn()?;
201
202let mut mcp = McpClient::new(transport);
203mcp.initialize().await?;
204let r = mcp.call_tool("ping", json!({})).await?;
205mcp.close().await?;   // graceful: drops stdin, waits 5s, then SIGKILL`},{label:"Custom transport",lang:"rust",code:`use async_trait::async_trait;
206use cognitum_one::mcp::{JsonRpcMessage, McpError, Transport};
207
208struct WebsocketTransport { /* ... */ }
209
210#[async_trait]
211impl Transport for WebsocketTransport {
212    async fn send(&mut self, msg: JsonRpcMessage) -> Result<(), McpError> {
213        // serialize + write to the WS sink
214        Ok(())
215    }
216    async fn recv(&mut self) -> Result<JsonRpcMessage, McpError> {
217        // read + deserialize
218        Ok(JsonRpcMessage::default())
219    }
220    async fn close(&mut self) -> Result<(), McpError> {
221        Ok(())
222    }
223}`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"cloud-brain",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Cloud · Brain"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-3",children:"Shared knowledge base — share memories, search semantically, vote on usefulness."}),e.jsx(t,{tabs:[{label:"Share",lang:"rust",code:`let r = client.brain()
224    .share(
225        "fall back to seed-stream when esp32-uart goes silent for >2s",
226        Some("ops"),                           // namespace (optional)
227        Some(vec!["sensor".into(), "fallback".into()]),  // tags (optional)
228    )
229    .await?;
230println!("memory id = {:?}", r.id);`},{label:"Search",lang:"rust",code:`let r = client.brain()
231    .search("fallback patterns", Some("ops"), Some(10))
232    .await?;
233for m in r.results {
234    let score = m.score.unwrap_or(0.0);
235    println!("{:.3}  {}", score, m.content);
236}`},{label:"Vote",lang:"rust",code:`// vote: 1 (up) or -1 (down). The endpoint accepts an i8.
237client.brain().vote("memory-id-abc", 1).await?;
238client.brain().vote("memory-id-xyz", -1).await?;`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"seed-connect",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Seed · Connect"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["Behind ",e.jsx("code",{className:"font-mono text-xs",children:"--features seed"}),". Six resource accessors hang off"," ",e.jsx("code",{className:"font-mono text-xs",children:"SeedClient"}),": ",e.jsx("code",{className:"font-mono text-xs",children:"pair"}),","," ",e.jsx("code",{className:"font-mono text-xs",children:"store"}),", ",e.jsx("code",{className:"font-mono text-xs",children:"witness"}),","," ",e.jsx("code",{className:"font-mono text-xs",children:"custody"}),", ",e.jsx("code",{className:"font-mono text-xs",children:"ota"}),","," ",e.jsx("code",{className:"font-mono text-xs",children:"mesh"}),". Plus top-level ",e.jsx("code",{className:"font-mono text-xs",children:"status()"})," ","/ ",e.jsx("code",{className:"font-mono text-xs",children:"identity()"}),", ",e.jsx("code",{className:"font-mono text-xs",children:"session()"}),","," ",e.jsx("code",{className:"font-mono text-xs",children:"peers()"}),", ",e.jsx("code",{className:"font-mono text-xs",children:"rediscover()"}),"."," ",e.jsx("code",{className:"font-mono text-xs",children:"SeedClient"})," is ",e.jsx("code",{className:"font-mono text-xs",children:"Clone"})," — its inner state lives behind an ",e.jsx("code",{className:"font-mono text-xs",children:"Arc"}),", so cloning is cheap."]}),e.jsx(t,{tabs:[{label:"Single endpoint",lang:"rust",code:`use cognitum_one::seed::{SeedAuth, SeedClient, SeedTls};
239
240let client = SeedClient::builder()
241    .endpoint("https://cognitum.local:8443")
242    .tls(SeedTls::Insecure)              // dev-only — see Seed · TLS
243    .auth(SeedAuth::pairing_token(
244        std::env::var("SEED_BEARER")?,
245    ))
246    .max_retries(3)
247    .build()?;
248
249let status = client.status().await?;
250println!("seed {} v{} epoch {}",
251         status.device_id, /* firmware via identity */ "", status.epoch);
252
253// SeedClient is Clone — cheap to share across tasks.
254let bg = client.clone();
255tokio::spawn(async move {
256    let _ = bg.status().await;
257});`},{label:"Multiple peers (mesh)",lang:"rust",code:`use cognitum_one::seed::{SeedClient, SeedTls, Routing};
258
259// Phase 1.5: closest-first session-sticky reads, cycle-on-5xx
260// failover, pin-on-429 backoff. Order is preserved as the
261// list-index tie-breaker.
262let client = SeedClient::builder()
263    .endpoints(&[
264        "https://10.0.0.10:8443",
265        "https://10.0.0.11:8443",
266        "https://10.0.0.12:8443",
267    ])
268    .routing(Routing::Session)            // default
269    .tls(SeedTls::Insecure)
270    .build()?;
271
272// Pinned session for read-your-writes within a logical scope:
273let session = client.session();
274let _ss = session.store().status().await?;`},{label:"Inspect / lifecycle",lang:"rust",code:`// What peers does the client know about?
275let peers = client.peers();
276println!("{} peers configured", peers.len());
277
278// Re-run the configured Discovery provider (or, when none is
279// installed, reset all peers to Healthy and clear EMAs).
280client.rediscover().await?;
281
282// Pinned session — see "Seed · Connect"; sticky reads come from
283// here (read-your-writes within the session lifetime).
284let session = client.session();
285println!("pinned to {}", session.pinned_peer());
286
287// SeedClient drops the per-process active health probe on Drop;
288// no explicit close() needed.`},{label:"Active health probe",lang:"rust",code:`use std::time::Duration;
289
290// Opt-in background poller (ADR-0016a §D7). Pings GET /api/v1/status
291// on every peer at the given interval and feeds the routing layer's
292// PeerSet so latency / health stay fresh even when the caller is idle.
293let client = SeedClient::builder()
294    .endpoints(&["https://s1:8443", "https://s2:8443"])
295    .tls(SeedTls::Insecure)
296    .health_interval(Duration::from_secs(30))
297    .build()?;`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"seed-call-options",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Seed · Per-call options"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["Every resource method has a ",e.jsx("code",{className:"font-mono text-xs",children:"_with(opts: CallOptions)"})," twin that takes a typed ",e.jsx("code",{className:"font-mono text-xs",children:"CallOptions"})," bag."," ",e.jsx("code",{className:"font-mono text-xs",children:"CallOptions::default()"})," is a no-op — calling"," ",e.jsx("code",{className:"font-mono text-xs",children:"_with"})," with default options behaves identically to its parameterless twin."]}),e.jsx(t,{tabs:[{label:"Type",lang:"rust",code:`use std::time::Duration;
298use cognitum_one::seed::{CallOptions, Consistency, Prefer};
299
300pub struct CallOptions {
301    /// Pin this one call to a specific peer URL.
302    /// Must be in the configured PeerSet — otherwise Error::Validation
303    /// with prefix "config: peer not in mesh: ...".
304    pub peer: Option<String>,
305
306    /// Override the closest-first picker for this call only.
307    pub prefer: Option<Prefer>,        // Closest | LocalFirst | Random | Any
308
309    /// Consistency posture. Strong returns Error::Validation
310    /// with prefix "unsupported:" (the seed has no quorum layer).
311    pub consistency: Option<Consistency>,  // Session | Eventual | Strong
312
313    /// Per-call read timeout override. Connect / total budgets are
314    /// untouched.
315    pub timeout: Option<Duration>,
316
317    /// Per-call retry override. None = builder default,
318    /// Some(0) = no retries.
319    pub retries: Option<u32>,
320}`},{label:"Examples",lang:"rust",code:`use std::time::Duration;
321use cognitum_one::seed::{CallOptions, Consistency, Prefer, StoreQuery};
322
323// Pin to a specific peer:
324let opts = CallOptions::new()
325    .peer("https://10.0.0.11:8443");
326let r = client.store().query_with(
327    StoreQuery { vector: emb.clone(), k: 5 },
328    opts,
329).await?;
330
331// Prefer LAN peers:
332let opts = CallOptions::new().prefer(Prefer::LocalFirst);
333client.store().query_with(StoreQuery { vector: emb.clone(), k: 5 }, opts).await?;
334
335// Drop session-stickiness for one call:
336let opts = CallOptions::new().consistency(Consistency::Eventual);
337client.store().status_with(opts).await?;
338
339// Custom timeout + zero retries:
340let opts = CallOptions::new()
341    .timeout(Duration::from_secs(60))
342    .retries(0);
343// (returns Err for non-idempotent paths if the call fails)
344client.pair().create_with(req, opts).await?;`},{label:"Strong is unsupported",lang:"rust",code:`use cognitum_one::Error;
345use cognitum_one::seed::{CallOptions, Consistency};
346
347// The seed has no quorum layer. Asking for Strong fails fast,
348// before any network I/O, with a clean validation error.
349let opts = CallOptions::new().consistency(Consistency::Strong);
350match client.store().status_with(opts).await {
351    Err(Error::Validation(msg)) if msg.starts_with("unsupported:") => {
352        eprintln!("seed cannot do strong reads: {msg}");
353    }
354    other => panic!("unexpected: {other:?}"),
355}`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"seed-tls",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Seed · TLS"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:[e.jsx("code",{className:"font-mono text-xs",children:"SeedTls"})," has three modes — ",e.jsx("code",{className:"font-mono text-xs",children:"System"})," ","(webpki / OS roots, default), ",e.jsx("code",{className:"font-mono text-xs",children:"Pinned(Vec<u8>)"})," (single PEM CA, disables system roots), and ",e.jsx("code",{className:"font-mono text-xs",children:"Insecure"})," (dev-only). When discovery surfaces ",e.jsx("code",{className:"font-mono text-xs",children:"fp=sha256:<hex>"})," TXT entries, the SDK installs a custom"," ",e.jsx("code",{className:"font-mono text-xs",children:"FingerprintPinVerifier"})," on top of the chosen mode."]}),e.jsx(t,{tabs:[{label:"Pinned CA",lang:"rust",code:`use cognitum_one::seed::{SeedClient, SeedTls};
356
357let pem = std::fs::read("./cognitum-ca.pem")?;
358let client = SeedClient::builder()
359    .endpoint("https://cognitum.local:8443")
360    .tls(SeedTls::Pinned(pem))         // single root; system trust off
361    .build()?;`},{label:"Fingerprint pin (mDNS)",lang:"rust",code:`// When mDNS-discovered peers advertise \`fp=sha256:<hex>\`, the SDK
362// builds a per-peer pin map and installs a rustls verifier that
363// strict-checks pinned peers and falls back to webpki-roots for
364// unpinned peers. fp= advertisements are NORMALIZED — colons and
365// case are stripped — so "sha256:AA:BB:CC" and "aabbcc" compare equal.
366//
367// A peer presenting a cert whose SHA-256 doesn't match the pin
368// fails the handshake with rustls::Error::General("fingerprint pin
369// mismatch for <host>"); the SDK surfaces the exact shape in
370// Error::Validation("tls_pin: fingerprint mismatch for ...").
371
372#[cfg(feature = "mdns")]
373{
374    use cognitum_one::seed::{MdnsDiscovery, SeedClient, SeedTls};
375
376    let client = SeedClient::builder()
377        .discovery(MdnsDiscovery::new())   // emits fp= per peer
378        .tls(SeedTls::System)              // pinned peers + webpki for the rest
379        .build()?;
380}`},{label:"Insecure (dev only)",lang:"rust",code:`use cognitum_one::seed::{SeedClient, SeedTls};
381
382// One-shot stderr warning per process. Mutually exclusive with
383// SeedTls::Pinned — the rustls verifier wiring is different.
384//
385// NEVER use this in production. Prefer SeedTls::Pinned for
386// self-signed seeds, or fp=-pinning via mDNS.
387let client = SeedClient::builder()
388    .endpoint("https://localhost:18443")
389    .tls(SeedTls::Insecure)
390    .build()?;`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"seed-pair",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Seed · Pair"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["A pairing token is required for any write — store ingest, OTA actions, mutating mesh ops. The seed enforces a 30-second pairing window opened by the operator (e.g. via the on-device"," ",e.jsx("code",{className:"font-mono text-xs",children:"/store"})," UI or the ",e.jsx("code",{className:"font-mono text-xs",children:"POST /api/v1/pair/window"})," ","endpoint). Inside that window, ",e.jsx("code",{className:"font-mono text-xs",children:"pair().create()"})," mints a token."]}),e.jsx(t,{tabs:[{label:"Status",lang:"rust",code:`let s = client.pair().status().await?;
391println!("paired={}, clients={}, window_open={}, secs_left={}",
392         s.paired, s.client_count, s.pairing_window_open, s.window_remaining_secs);`},{label:"Create token",lang:"rust",code:`use cognitum_one::seed::PairCreate;
393
394let resp = client.pair().create(PairCreate {
395    client_name: "my-laptop".into(),
396}).await?;
397
398// resp.token is a SecretString — the Debug impl redacts. Use
399// .as_str() at the request boundary; never println!("{:?}", resp.token)
400// unredacted.
401let token = resp.token.as_str().to_owned();
402let expires_at = resp.expires_at.as_deref().unwrap_or("never");
403println!("paired as {} (expires {})", resp.client_name, expires_at);
404
405// Re-construct the client with the bearer for paired ops:
406use cognitum_one::seed::{SeedAuth, SeedClient, SeedTls};
407
408let paired = SeedClient::builder()
409    .endpoint("https://cognitum.local:8443")
410    .tls(SeedTls::Insecure)
411    .auth(SeedAuth::pairing_token(token))
412    .build()?;`},{label:"Delete (unpair)",lang:"rust",code:`// Revoke by client_name. The seed deletes the per-client record.
413client.pair().delete("my-laptop").await?;`},{label:"Per-peer tokens",lang:"rust",code:`use cognitum_one::seed::{InMemoryTokenBook, SecretString, SeedClient, SeedTls};
414
415// Build a per-peer TokenBook for a multi-seed mesh — the
416// per-peer entry takes priority over the client-wide SeedAuth.
417let book = InMemoryTokenBook::from_map([
418    ("https://10.0.0.10:8443", "bearer-1"),
419    ("https://10.0.0.11:8443", "bearer-2"),
420]);
421
422let client = SeedClient::builder()
423    .endpoints(&["https://10.0.0.10:8443", "https://10.0.0.11:8443"])
424    .tls(SeedTls::Insecure)
425    .token_book(book)
426    .build()?;`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"seed-status",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Seed · Status / Identity"}),e.jsx(t,{tabs:[{label:"Status",lang:"rust",code:`let s = client.status().await?;
427println!("device_id   = {}", s.device_id);
428println!("uptime_secs = {}", s.uptime_secs);
429println!("epoch       = {}", s.epoch);
430println!("vectors     = {} (deleted {})", s.total_vectors, s.deleted_vectors);
431println!("dimension   = {}", s.dimension);
432println!("paired      = {}", s.paired);
433println!("roles       = {:?}", s.roles);
434// Forward-compat: any field the firmware adds later is captured here.
435if !s.extras.is_empty() {
436    println!("extras      = {:?}", s.extras);
437}`},{label:"Identity",lang:"rust",code:`let id = client.identity().await?;
438println!("device_id        = {}", id.device_id);
439println!("public_key       = {}", id.public_key);
440println!("firmware_version = {}", id.firmware_version);`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"seed-store",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Seed · Store (RVF vector store)"}),e.jsx(t,{tabs:[{label:"Status",lang:"rust",code:`let s = client.store().status().await?;
441println!("{} vectors (deleted {}), dim {}, file_size {} bytes",
442         s.total_vectors, s.deleted_vectors, s.dimension, s.file_size_bytes);`},{label:"Query (kNN)",lang:"rust",code:`use cognitum_one::seed::StoreQuery;
443
444let r = client.store().query(StoreQuery {
445    vector: vec![0.1, 0.2, /* ... */ 0.8],
446    k: 5,
447}).await?;
448
449println!("query_ms = {:.2}", r.query_ms);
450for hit in &r.results {
451    println!("id={:>20}
451  distance={:.4}  metadata={}",
452             hit.id, hit.distance, hit.metadata);
453}`},{label:"Ingest",lang:"rust",code:`use cognitum_one::seed::{StoreIngest, StoreIngestEntry};
454use serde_json::json;
455
456let r = client.store().ingest(StoreIngest {
457    vectors: vec![
458        StoreIngestEntry {
459            id: "doc:1".into(),
460            values: vec![0.1, 0.2, 0.3],
461            metadata: Some(json!({ "source": "report-q1.pdf" })),
462        },
463        StoreIngestEntry {
464            id: "doc:2".into(),
465            values: vec![0.4, 0.5, 0.6],
466            metadata: Some(json!({ "source": "report-q2.pdf" })),
467        },
468    ],
469}).await?;
470println!("ingested {}", r.ingested);`},{label:"Idempotency",lang:"rust",code:`// store.query() is declared idempotent in the SDK — it's a
471// read-with-body and the seed has no per-request side effects. The
472// SDK retries it on 5xx / network errors automatically.
473//
474// store.ingest() is NOT idempotent: an ingest produces a witness
475// chain entry, so retrying changes server state. The SDK never
476// auto-retries non-idempotent POSTs; if you've designed your batch
477// to be safe to retry (e.g. content-hashed IDs), opt in via
478// CallOptions.
479use cognitum_one::seed::CallOptions;
480
481let opts = CallOptions::new().retries(0);  // explicit no-retry
482client.store().ingest_with(batch, opts).await?;`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"seed-witness",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Seed · Witness / Custody"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-3",children:"Both endpoints are allowlisted reads — no pairing required."}),e.jsx(t,{tabs:[{label:"Witness chain",lang:"rust",code:`// The wire shape changes per firmware (depth/epoch/head_hash on v0.20.x);
483// the SDK exposes a forward-compat catch-all via .extras instead of
484// baking field names that may churn.
485let chain = client.witness().chain().await?;
486for (key, value) in &chain.extras.0 {
487    println!("{key} = {value}");
488}`},{label:"Custody epoch",lang:"rust",code:`let e = client.custody().epoch().await?;
489println!("custody epoch = {}", e.epoch);`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"seed-ota",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Seed · OTA"}),e.jsx(t,{tabs:[{label:"Read config",lang:"rust",code:`let cfg = client.ota().config().await?;
490println!("OTA enabled = {} ({}, every {}s)",
491         cfg.enabled, cfg.channel, cfg.check_interval_secs);`},{label:"Check now",lang:"rust",code:`// v0.20.0+. Requires pairing token. Repeat-safe — the seed dedupes
492// internally — so the SDK marks it idempotent and may auto-retry on 5xx.
493let r = client.ota().check_now().await?;
494println!("triggered = {}", r.triggered);
495println!("message   = {}", r.message);
496println!("channel   = {}", r.channel);`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"seed-mesh",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Seed · Mesh"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["Phase 2 observability surface — four allowlisted reads on v0.20.0+. All four shapes carry a"," ",e.jsx("code",{className:"font-mono text-xs",children:"#[serde(flatten)] extras"})," sink so newer firmwares don't break the SDK."]}),e.jsx(t,{tabs:[{label:"Status",lang:"rust",code:`let m = client.mesh().status().await?;
497println!("ap_active={}, auto_mesh={}, peer_count={}",
498         m.ap_active, m.auto_mesh, m.peer_count);`},{label:"Peers",lang:"rust",code:`let p = client.mesh().peers().await?;
499println!("count={}, discovery={}", p.count, p.discovery_active);
500for raw in &p.peers {
501    println!("  {raw}");   // shape free-form on the wire today
502}`},{label:"Swarm + cluster",lang:"rust",code:`let s = client.mesh().swarm_status().await?;
503println!("swarm: epoch={} peers={} vectors={} uptime={}s",
504         s.epoch, s.peer_count, s.total_vectors, s.uptime_secs);
505
506let c = client.mesh().cluster_health().await?;
507println!("cluster_enabled={}, auto_sync={}s, last_attempt={}",
508         c.cluster_enabled, c.auto_sync_interval_secs, c.last_sync_attempt);`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"discovery",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Discovery providers"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["Pluggable peer discovery via the ",e.jsx("code",{className:"font-mono text-xs",children:"Discovery"})," trait. Pass a provider via ",e.jsx("code",{className:"font-mono text-xs",children:".discovery(...)"})," instead of (or alongside)"," ",e.jsx("code",{className:"font-mono text-xs",children:".endpoints(...)"}),"; the builder calls"," ",e.jsx("code",{className:"font-mono text-xs",children:"discover()"})," at construction, and"," ",e.jsx("code",{className:"font-mono text-xs",children:"SeedClient::rediscover()"})," re-runs it. Three providers ship today."]}),e.jsx(t,{tabs:[{label:"Explicit",lang:"rust",code:`use cognitum_one::seed::{Explicit, SeedClient, SeedTls};
509
510let discovery = Explicit::new(&[
511    "https://10.0.0.10:8443",
512    "https://10.0.0.11:8443",
513]);
514
515let client = SeedClient::builder()
516    .discovery(discovery)
517    .tls(SeedTls::Insecure)
518    .build()?;`},{label:"mDNS",lang:"rust",code:`// Requires --features seed,mdns
519#[cfg(feature = "mdns")]
520{
521    use cognitum_one::seed::{MdnsDiscovery, SeedClient, SeedTls};
522    use std::time::Duration;
523
524    let discovery = MdnsDiscovery::builder()
525        .service_type("_cognitum._tcp.local.")
526        .browse_duration(Duration::from_secs(2))
527        .build();
528
529    let client = SeedClient::builder()
530        .discovery(discovery)
531        .tls(SeedTls::System)         // fp= pins from TXT records strict-checked
532        .build()?;
533}`},{label:"Tailscale",lang:"rust",code:`// Always available — only depends on std::process::Command.
534// Shells out to \`tailscale status --json\` and walks Peer{}.
535use cognitum_one::seed::{SeedClient, SeedTls, TailscaleDiscovery};
536
537let discovery = TailscaleDiscovery::new()
538    .with_prefix("cognitum-")        // default
539    .with_port(8443);                // default
540
541let client = SeedClient::builder()
542    .discovery(discovery)
543    .tls(SeedTls::System)
544    .build()?;
545
546// Predicates (kept-or-dropped) — useful when your tailnet has
547// non-cognitum hosts whose names happen to match the prefix.
548let custom = TailscaleDiscovery::new()
549    .with_predicate(|p| {
550        p.online.unwrap_or(false)
551            && p.host_name.as_deref().is_some_and(|h| h.starts_with("seed-"))
552    });`},{label:"Custom provider",lang:"rust",code:`use async_trait::async_trait;
553use cognitum_one::seed::{DiscoveredPeer, Discovery};
554use cognitum_one::Error;
555
556#[derive(Debug)]
557struct ConsulDiscovery { /* ... */ }
558
559#[async_trait]
560impl Discovery for ConsulDiscovery {
561    async fn discover(&self) -> Result<Vec<DiscoveredPeer>, Error> {
562        // hit Consul's /v1/catalog/service/cognitum-seed
563        Ok(vec![
564            DiscoveredPeer::new("https://10.0.0.10:8443")
565                .with_device_id("seed-a")
566                .with_latency_ms(12),
567        ])
568    }
569}`},{label:"Rediscover",lang:"rust",code:`// Re-run the configured Discovery provider. New peers join the
570// PeerSet in Healthy state; peers no longer in the discovered list
571// are dropped. TokenBook entries for dropped peers are KEPT — a
572// transient discovery flap won't lose pairings. Session pins
573// survive if the pinned URL is still in the new list.
574client.rediscover().await?;
575
576// Without a Discovery provider configured, rediscover() resets
577// every existing peer to Healthy and clears latency EMAs / last_used_at.
578// No network I/O.`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"tokens",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Tokens (redaction-safe)"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["Pairing tokens are wrapped in ",e.jsx("code",{className:"font-mono text-xs",children:"SecretString"}),". The custom ",e.jsx("code",{className:"font-mono text-xs",children:"Debug"})," impl prints"," ",e.jsx("code",{className:"font-mono text-xs",children:"SecretString(<redacted, N bytes>)"}),"; the underlying buffer is best-effort zeroed on ",e.jsx("code",{className:"font-mono text-xs",children:"Drop"}),". Use"," ",e.jsx("code",{className:"font-mono text-xs",children:".as_str()"})," only at the request boundary."]}),e.jsx(t,{tabs:[{label:"SecretString",lang:"rust",code:`use cognitum_one::seed::SecretString;
579
580let tok = SecretString::new(std::env::var("SEED_BEARER")?);
581println!("{tok:?}");          // SecretString(<redacted, 64 bytes>)
582let bytes = tok.as_str();     // explicit unwrap — use sparingly`},{label:"InMemoryTokenBook",lang:"rust",code:`use cognitum_one::seed::{InMemoryTokenBook, SecretString, TokenBook};
583
584let mut book = InMemoryTokenBook::new();
585book.set("https://10.0.0.10:8443", SecretString::new("bearer-1"));
586book.set("https://10.0.0.11:8443", SecretString::new("bearer-2"));
587
588// Trailing slashes are normalized.
589assert_eq!(
590    book.get("https://10.0.0.10:8443/").unwrap().as_str(),
591    "bearer-1",
592);
593
594// Or build from any (peer, token) iterator:
595let book = InMemoryTokenBook::from_map([
596    ("https://a:8443", "tok-a"),
597    ("https://b:8443", "tok-b"),
598]);`},{label:"Custom TokenBook (keychain)",lang:"rust",code:`use cognitum_one::seed::{SecretString, TokenBook};
599use std::fmt;
600
601// Implement TokenBook to back tokens with the OS keychain, an
602// encrypted file, etc. The SDK calls get/set/delete under a Mutex
603// so single-threaded impls are fine.
604#[derive(Debug, Default)]
605struct KeychainBook;
606
607impl TokenBook for KeychainBook {
608    fn get(&self, peer_url: &str) -> Option<SecretString> {
609        // keychain.find(peer_url).ok().map(SecretString::new)
610        None
611    }
612    fn set(&mut self, peer_url: &str, token: SecretString) {
613        // keychain.set(peer_url, token.as_str())
614        let _ = (peer_url, token);
615    }
616    fn delete(&mut self, peer_url: &str) {
617        // keychain.delete(peer_url)
618        let _ = peer_url;
619    }
620}`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"errors",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Errors"}),e.jsxs("p",{className:"text-sm text-muted-foreground mb-3",children:["A single ",e.jsx("code",{className:"font-mono text-xs",children:"Error"})," enum (",e.jsx("code",{className:"font-mono text-xs",children:"cognitum_one::Error"}),") captures every failure shape. Variants are stable;
620 the seed module encodes additional metadata (auth reason, validation prefix, etc.) into the existing ",e.jsx("code",{className:"font-mono text-xs",children:"String"})," payloads via documented prefixes (",e.jsx("code",{className:"font-mono text-xs",children:"not_paired:"}),","," ",e.jsx("code",{className:"font-mono text-xs",children:"trust_score_blocked:"}),","," ",e.jsx("code",{className:"font-mono text-xs",children:"unsupported:"}),", ",e.jsx("code",{className:"font-mono text-xs",children:"tls_pin:"}),")."]}),e.jsx("div",{className:"border border-border/50 rounded-xl bg-card/30 overflow-hidden mb-4",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-card/50 text-muted-foreground text-xs uppercase tracking-wider",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left px-4 py-2 font-medium",children:"Variant"}),e.jsx("th",{className:"text-left px-4 py-2 font-medium",children:"When"})]})}),e.jsx("tbody",{children:[["Error::Auth(String)","401 / 403. Seed module prefixes with a reason: invalid_credentials, not_paired, pairing_window_closed, lockdown_mtls_required, trust_score_blocked."],["Error::RateLimit { retry_after_ms }","429. retry_after_ms is parsed from Retry-After header, body retry_after_us, body 'retry after Ns', or ADR-0005 equal-jitter fallback. Use err.retry_after() for a Duration."],["Error::Validation(String)","400 / 422 / 405. Also fired client-side for bad config. Seed module prefixes: 'config:', 'unsupported:', 'tls_pin:', 'not_implemented:'."],["Error::NotFound(String)","404. Seed module includes the request path in the message."],["Error::Api { code, message }","Catch-all for unmapped HTTP statuses (incl. 503 Service Unavailable). For seed transport: code=0 + message='seed: …' on transport-exhausted / lock-poisoned paths."],["Error::Http(reqwest::Error)","Underlying transport — DNS failure, connect refused, TLS handshake. Auto-converted via #[from]."],["Error::Json(serde_json::Error)","Response wasn't valid JSON or didn't deserialize into the expected shape. Auto-converted via #[from]."]].map(([s,i],a)=>e.jsxs("tr",{className:a%2?"bg-card/20":"",children:[e.jsx("td",{className:"px-4 py-2 align-top",children:e.jsx("code",{className:"font-mono text-xs text-primary",children:s})}),e.jsx("td",{className:"px-4 py-2 text-muted-foreground",children:i})]},s))})]})}),e.jsx(t,{tabs:[{label:"Match",lang:"rust",code:`use cognitum_one::Error;
621
622match client.orders().status("ord_does_not_exist").await {
623    Ok(orders) => println!("{} orders", orders.len()),
624    Err(Error::NotFound(msg)) => println!("no such order: {msg}"),
625    Err(Error::Auth(msg)) => println!("bad api key: {msg}"),
626    Err(Error::RateLimit { retry_after_ms }) => {
627        println!("slow down; retry in {retry_after_ms}ms");
628        // Or use err.retry_after() to get a Duration.
629    }
630    Err(Error::Validation(msg)) => println!("bad request: {msg}"),
631    Err(Error::Http(e)) => println!("net error: {e}"),
632    Err(Error::Json(e)) => println!("decode error: {e}"),
633    Err(Error::Api { code, message }) => println!("API {code}: {message}"),
634}`},{label:"Seed prefix detection",lang:"rust",code:`use cognitum_one::Error;
635
636// Seed-specific reasons are encoded as documented prefixes inside the
637// existing String variants. Detect them with starts_with — the prefixes
638// are stable across SDK versions.
639match client.store().ingest(req).await {
640    Err(Error::Auth(msg)) if msg.starts_with("not_paired:") => {
641        eprintln!("open a pairing window first");
642    }
643    Err(Error::Auth(msg)) if msg.starts_with("trust_score_blocked:") => {
644        // 3rd consecutive auth failure on this peer — the seed has
645        // locked us out. Don't retry.
646        eprintln!("peer locked us out: {msg}");
647    }
648    Err(Error::Validation(msg)) if msg.starts_with("tls_pin:") => {
649        eprintln!("cert fingerprint mismatch: {msg}");
650    }
651    Err(Error::Validation(msg)) if msg.starts_with("unsupported:") => {
652        eprintln!("seed cannot do this: {msg}");
653    }
654    Err(Error::Validation(msg)) if msg.starts_with("not_implemented:") => {
655        eprintln!("endpoint missing on this firmware: {msg}");
656    }
657    other => {
658        let _ = other?;
659    }
660}`},{label:"Retry-After helper",lang:"rust",code:`use cognitum_one::Error;
661
662if let Err(err) = client.health().await {
663    if let Some(delay) = err.retry_after() {
664        // Wait the server-suggested delay, then retry.
665        tokio::time::sleep(delay).await;
666        let _ = client.health().await;
667    } else {
668        return Err(err);
669    }
670}`}]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"features",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Cargo features"}),e.jsx("div",{className:"border border-border/50 rounded-xl bg-card/30 overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-card/50 text-muted-foreground text-xs uppercase tracking-wider",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left px-4 py-2 font-medium",children:"Feature"}),e.jsx("th",{className:"text-left px-4 py-2 font-medium",children:"Default"}),e.jsx("th",{className:"text-left px-4 py-2 font-medium",children:"Effect"})]})}),e.jsx("tbody",{children:[["rustls","yes","rustls TLS via reqwest/rustls-tls. Rust-native, no OpenSSL dependency."],["native-tls","no","Use the platform's TLS stack instead of rustls (SChannel on Windows, SecureTrans
670port on macOS, OpenSSL on Linux). Pair with default-features = false."],["seed","no","Enables the cognitum_one::seed module — SeedClient, mesh routing, TLS pinning, CallOptions, Discovery trait, TokenBook, SeedSession, SecretString. Pulls in url for endpoint parsing."],["mdns","no","mDNS / DNS-SD discovery via mdns-sd (one-shot _cognitum._tcp.local. browse). Implies seed."],["stream","no","SSE streaming via eventsource-stream for the seed delta-stream endpoint. Implies seed."],["blocking","no","reqwest's blocking client (no tokio runtime needed for cloud calls)."],["live-seed-tests","no","Opt-in integration tests that hit a real seed at $SEED_URL. Implies seed. CI-only."]].map(([s,i,a],u)=>e.jsxs("tr",{className:u%2?"bg-card/20":"",children:[e.jsx("td",{className:"px-4 py-2 align-top whitespace-nowrap",children:e.jsx("code",{className:"font-mono text-xs text-primary",children:s})}),e.jsx("td",{className:"px-4 py-2 align-top text-muted-foreground whitespace-nowrap",children:i}),e.jsx("td",{className:"px-4 py-2 text-muted-foreground",children:a})]},s))})]})}),e.jsxs("p",{className:"text-[12px] text-muted-foreground mt-3",children:["The Tailscale discovery provider has ",e.jsx("em",{children:"no"})," feature flag — it only depends on"," ",e.jsx("code",{className:"font-mono text-xs",children:"std::process::Command"})," and"," ",e.jsx("code",{className:"font-mono text-xs",children:"tokio::task::spawn_blocking"}),", both unconditionally available under ",e.jsx("code",{className:"font-mono text-xs",children:"--features seed"}),". On platforms without a"," ",e.jsx("code",{className:"font-mono text-xs",children:"tailscale"})," binary on PATH, calls return"," ",e.jsx("code",{className:"font-mono text-xs",children:"Error::Validation"}),"."]})]}),e.jsxs("section",{children:[e.jsx("h2",{id:"related",className:"text-2xl font-bold text-foreground mb-3 scroll-mt-24",children:"Related"}),e.jsxs("ul",{className:"text-sm text-muted-foreground space-y-2 list-disc pl-5",children:[e.jsxs("li",{children:[e.jsx(n,{to:"/sdks/javascript",className:"text-primary hover:underline",children:"JavaScript SDK"})," — same surface, Node.js / TypeScript, mDNS / USB / LAN discovery."]}),e.jsxs("li",{children:[e.jsx(n,{to:"/sdks/python",className:"text-primary hover:underline",children:"Python SDK"})," — sync + async with the same shape."]}),e.jsxs("li",{children:[e.jsx(n,{to:"/sdks/claude-code",className:"text-primary hover:underline",children:"Claude Code plugins"})," — marketplace plugins for cloud + seed."]}),e.jsxs("li",{children:[e.jsx(n,{to:"/api",className:"text-primary hover:underline",children:"REST API reference"})," — underlying HTTP surface."]})]}),e.jsxs("div",{className:"mt-5 flex flex-wrap gap-2",children:[e.jsxs("a",{href:"https://crates.io/crates/cognitum-one",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-border/50 bg-card/50 hover:border-border text-sm text-foreground transition-colors",children:[e.jsx(l,{className:"h-4 w-4"}),"crates.io/crates/cognitum-one",e.jsx(c,{className:"h-3 w-3 text-muted-foreground"})]}),e.jsxs("a",{href:"https://docs.rs/cognitum-one",target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-border/50 bg-card/50 hover:border-border text-sm text-foreground transition-colors",children:[e.jsx(c,{className:"h-4 w-4"}),"docs.rs/cognitum-one"]})]})]})]})})})}),e.jsx(h,{})]})]})}export{le as SdkRustPage,le as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.